Skip to content

Instantly share code, notes, and snippets.

@alskipp
Last active August 29, 2015 14:14
Show Gist options
  • Save alskipp/0a76969bdc6e10727f83 to your computer and use it in GitHub Desktop.
Save alskipp/0a76969bdc6e10727f83 to your computer and use it in GitHub Desktop.
Swift cat care with enums and protocols (+ Haskell for a varied diet)
type MilliLitresWaterPerGram = Double
type CaloriesPerGram = Double
type Grams = Double
data Food = Dry CaloriesPerGram
| Wet CaloriesPerGram MilliLitresWaterPerGram
deriving (Show, Eq)
data Animal = Cat { clawLength :: Double, calorieCount :: Double, hydrationLevel :: Double }
| Dog { barkVolume :: Double, calorieCount :: Double, hydrationLevel :: Double }
deriving (Show, Eq)
eat :: Animal -> Food -> Grams -> Animal
eat a food grams = case food of
(Dry g) -> mkAnimal a (cal g) (hydrationLevel a)
(Wet g m) -> mkAnimal a (cal g) (hyd m)
where cal g = (calorieCount a) + g * grams
hyd m = (hydrationLevel a) + m * grams
mkAnimal :: Animal -> Double -> Double -> Animal
mkAnimal (Cat claw _ _) = Cat claw
mkAnimal (Dog bark _ _) = Dog bark
kibble = Dry 40
fancyFeast = Wet 80 0.2
dave = Cat {clawLength = 15, calorieCount = 100, hydrationLevel = 10}
bigDave = eat dave kibble 100
deadDave = eat bigDave fancyFeast 50
beasts = [(Cat 12 100 10), (Cat 20 50 5), (Dog 100 200 20)]
caloriesAfterKibbleSnack :: [Animal] -> Double
caloriesAfterKibbleSnack = sum . map (\a -> calorieCount $ eat a kibble 10)
enum Food {
case Dry(caloriesPerGram:Double)
case Wet(caloriesPerGram:Double, milliLitresWaterPerGram:Double)
}
let kibble = Food.Dry(caloriesPerGram: 40)
let fancyFeast = Food.Wet(caloriesPerGram: 80, milliLitresWaterPerGram: 0.2)
struct Cat {
let calorieCount: Double = 100
let hydrationLevel: Double = 10
}
extension Cat {
func eat(food: Food, grams: Double) -> Cat {
let newCals = { calsPerGram in self.calorieCount + grams * calsPerGram }
let newHyd = { milsPerGram in self.hydrationLevel + grams * milsPerGram }
switch food {
case .Dry(let caloriesPerGram) :
return Cat(calorieCount: newCals(caloriesPerGram), hydrationLevel: hydrationLevel)
case .Wet(let caloriesPerGram, let milliLitresWaterPerGram) :
return Cat(calorieCount: newCals(caloriesPerGram), hydrationLevel: newHyd(hydrationLevel))
}
}
}
var dave = Cat()
dave = dave.eat(kibble, grams: 30)
dave = dave.eat(fancyFeast, grams: 20)
protocol Food {
var caloriesPerGram: Double {get}
}
protocol WetGrub: Food {
var milliLitresWaterPerGram: Double {get}
}
struct Kibble: Food {
let caloriesPerGram: Double = 40
}
struct FancyFeast: WetGrub {
let caloriesPerGram: Double = 80
let milliLitresWaterPerGram: Double = 0.2
}
struct Cat {
let calorieCount: Double = 100
let hydrationLevel: Double = 10
}
extension Cat {
func eat(food: Food, grams: Double) -> Cat {
let c = calorieCount + grams * food.caloriesPerGram
return Cat(calorieCount: c, hydrationLevel: hydrationLevel)
}
func eat(food: WetGrub, grams: Double) -> Cat {
let c = calorieCount + grams * food.caloriesPerGram
let h = hydrationLevel + grams * food.milliLitresWaterPerGram
return Cat(calorieCount: c, hydrationLevel: h)
}
}
let catFood = Kibble()
let wetFood = FancyFeast()
var dave = Cat()
dave = dave.eat(catFood, grams: 30)
dave = dave.eat(wetFood, grams: 20)
@alskipp
Copy link
Author

alskipp commented Feb 1, 2015

Here are two alternative approaches of solving a multiple protocol problem in Swift. The following blog post by Ash Furrow is a really interesting read and explains the issue well:
http://ashfurrow.com/blog/protocols-and-swift/

@alskipp
Copy link
Author

alskipp commented Feb 5, 2015

Added a Haskell implementation that can feed varied beasts – inspired by David Owens II’s, Swift implementation, here: http://owensd.io/2015/02/02/swift-and-protocols.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment