Last active
August 29, 2015 14:14
-
-
Save alskipp/0a76969bdc6e10727f83 to your computer and use it in GitHub Desktop.
Swift cat care with enums and protocols (+ Haskell for a varied diet)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
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
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/