Haskell data types with type variables - haskell

I have been going through tutorial examples for data types and I have defined the following:
ghci> data Animal a b = Cat a | Dog b | Rat
ghci> data BreedOfCat = Siamese | Persian | Moggie
ghci> :t Cat Siamese
Cat Siamese :: Animal BreedOfCat b
ghci> :t Cat Persian
Cat Persian :: Animal BreedOfCat b
ghci> :t Dog 12
Dog 12 :: Num b => Animal a b
ghci> :t Dog "Fifo"
Dog "Fifo" :: Animal a String
ghci> :t Rat
Rat :: Animal a b
If Dog "Fifo" gives Animal a String, why doesn't Dog 12 give Animal a Integer (which is what the tutorial says it should)

It basically does. It just does not pick a specific type for the 12, this can be any type that is a member of the Num typeclass, hence Num b => Animal a b. If you force to pick an Integer for 12, it will, indeed:
ghci> :t Dog (12 :: Integer)
Animal a Integer

Related

Modify Haskell nested record by value

Say I have a nested structure as follows:
data Bar = Bar { _id :: Integer, _bars :: [Bar] }
data Foo = Foo { _bars :: [Bar] }
And I have a Foo with a bunch of Bars with various ids:
foo = Foo [Bar 1 [Bar 2], Bar 3 [Bar 4, Bar 5]]
How do, perhaps using lenses, I modify foo such that Bar 5 becomes Bar 6?
I know I use fclabels to do something like this:
mkLabel ''Foo
mkLabel ''Bar
modify bars (\bars -> ...) foo
But bars can be nested infinitely. How do I locate and modify the Bar with a specified ID?
Yep, lens can do that. The Control.Lens.Plated module contains tools for "Scrap Your Boilerplate"-style programming with self-similar structures like your Bar. The idea is seductively simple: you explain how to find the immediate children of a node (by writing a Traversal' a a) and the library recursively applies that traversal to the whole structure.
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
data Bar = Bar { _lbl :: Int, _bars :: [Bar] } deriving (Show)
makeLenses ''Bar
instance Plated Bar where
plate = bars.traverse
(If you don't want to implement plate yourself, you can derive Data and leave the instance empty.)
transform :: Plated a => (a -> a) -> a -> a takes a function which modifies a single node and applies it to the whole structure.
fiveToSix :: Bar -> Bar
fiveToSix = transform go
where go bar
| bar^.lbl == 5 = bar & lbl .~ 6
| otherwise = bar
Using the example from your question:
ghci> let bars = [Bar 1 [Bar 2 []], Bar 3 [Bar 4 [], Bar 5 []]]
ghci> map fiveToSix bars
[Bar 1 [Bar 2 []], Bar 3 [Bar 4 [], Bar 6 []]]
As another example, for funzies, let's use cosmos to pull all of the Bar 5s out of a Bar.
fives :: Bar -> [Bar]
fives = toListOf $ cosmos.filtered (views lbl (== 5))

Lenses with Sum Types (that have Product types)

{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
data Fruit = Fruit
{ _fruitColor :: String
}
$(makeClassy ''Fruit)
data Fruits =
Banana Int Fruit
| Strawberry String Fruit
printer :: HasFruit s => s -> IO ()
printer f = putStrLn $ f ^. fruitColor
sample :: IO ()
sample = do
printer $ Fruit "yellow"
printer $ Banana 5 $ Fruit "yellow"
I have a core product type, Fruit. I want to have data types that all contain the core product type, Fruit, but want to be able to have them represented by a sum type, Fruits. Using the sum type, Fruits, I'd like to be able to access components of the core product type, Fruit. Namely, I'd like types like Banana and Strawberry to be an instance of HasFruit.
Is there a straightforward way to have Fruits instantiate HasFruit? Is there a better pattern to represent this - core product type in a sum type?
It would make more sense to do something like this:
data FruitType = Banana Int | Strawberry String
data Fruits = Fruits { _fruitsFruitType :: FruitType, _fruitsFruit :: Fruit }
makeFields ''Fruits
-- `Fruits` now instantiates `HasFruit`
You might also want to make prisms for FruitType. Prisms are essentially traversals into different parts of a sum type, except they can also be used to construct it.
makePrisms ''FruitType
-- double the int if the argument is a `Banana`
doubleBanana = fruitType._Banana *~ 2

Is there a generic function that takes a data structure and returns all ints in it?

I think the type signature would look like f :: a -> [Int]
input data would look like data NamedPoint = NamedPoint String Int Int
data Person = Name Int Int Int
and using it in the REPL would look like this:
>> let namedPoint = NamedPoint "hey" 1 2
>> let tommy = Person "Tommy" 1 2 3
>> f namedPoint
>> [1,2]
>> f Tommy
>> [1,2,3]
I think this would be useful as an alternative to records for when you are too lazy to write getters for data with alot of parameters.
The Data class is capable of this. I've found the easiest way to work with it is with the template traversal from the lens package. This essentially lets you set or get anything with a Data instance. In ghci:
> import Data.Data
> import Control.Lens
> import Data.Data.Lens
> -- Data is a derivable class
> :set -XDeriveDataTypeable
> data NamedPoint = NamedPoint String Int Int deriving (Data, Show)
> data Person = Name String Int Int Int deriving (Data, Show)
> let namedPoint = NamedPoint "hey" 1 2
> let tommy = Name "Tommy" 1 2 3
> let ints = toListOf template :: Data a => a -> [Int]
> ints namedPoint
[1,2]
> ints tommy
[1,2,3]
Because template is a traversal, you can also map over values (but you may need to specify the type):
> namedPoint & template *~ (10 :: Int)
NamedPoint "hey" 10 20
> import Data.Char
> tommy & template %~ toUpper
Name "TOMMY" 1 2 3
This is not possible with a function of the type signature you described. Think about what the f :: a -> [Int] means: f is supposed to be a function that takes a value of any possible type and returns a list of Ints. How should such a function be defined? The only possible definition is that it ignores the argument and returns a constant value, something like
f :: a -> [Int]
f _ = [0]
If you know what your a is going to be, why not just use that type? Like this:
f :: NamedPoint -> [Int]
f (NamedPoint _ a b) = [a, b]
If you wanted some "general" function returning all Ints from a datatype, one option would be to define a typeclass
class IntContainer a where
f :: a -> [Int]
and then define instances for the datatypes you are interested in
instance IntContainer NamedPoint where
f (NamedPoint _ a b) = [a, b]

Accessing elements of custom type variables in Haskell?

I have a type called Animal which includes the animal's family and the color of the animal.
type Animal family = [(family, color)]
data Family = Ape | Bear | Bird | Cat | Dog | Chicken
data Color = Brown | Black | White | Other
I also have a function in which I am trying to access the family and color of an animal. All I am asking is simply how to access these elements from within a function. For example in most object oriented languages we would access these elements with something like animal.family.
animalFunction :: Animal -> String
animalFunction animal
| animal.family == Ape = "This animal is an ape."
type Animal family = [(family, color)]
First and foremost, this shouldn't compile; would if changed to [(family, Color)]
This is a type alias, stating that Animal means a list of tuples1 of (parametrized family type, color), which is most probably not what you want.
As #rightfold suggested, you probably wanted
data Animal = Animal Family Color
Or, using record syntax:
data Animal = Animal { family :: Family, color :: Color }
Then, your function:
-- record version
animalFunction :: Animal -> String
animalFunction animal
| family animal == Ape = "This animal is an ape."
| ...
Note: family :: Animal -> Family
Or you can just pattern match2.
animalFunction (Animal f c)
| f == Ape = ...
or even:
animalFunction (Animal Ape _) = ...
However, what you're probably looking for is Show, as a general, idiomatic way to convert something to String3.
data Family = Ape | Bear | Bird | Cat | Dog | Chicken deriving (Show)
instance Show Animal where
show (Animal f _) = "This animal is an " ++ (show f) ++ "."
1 Pairs.
2 It works with both records and non-records, because records only really introduce getters of type Record -> Member for every member, and they don't modify the structure
3 In other languages, you can think about this as implementing "ToString" interface for your class. It's an oversimplification, but enough to understand this example.
To test for cases of an algebraic data type you should use pattern matching instead of if statements or guards:
case myFamily of
Ape -> "This is an ape"
Bear -> "Dangerous carnivore!"
Bird -> "This can fly"
-- and so on...

Haskell - Calling a function defined in a typeclass

Given a typeclass:
class AnimalTrainer animal food where
getFood :: animal -> (food, Int) -- Returns the food and the quantity
feed :: animal -> (food, Int) -- Returns the leftovers
feed a = feed' (getFood a) -- Provide a default implementation
where feed' (f, n) = (f, n - 1)
And an instance:
data Animal = Dog | Cat
data Food = Meat | Milk
instance AnimalTrainer Animal Food where
getFood Dog = (Meat, 2)
getFood Cat = (Milk, 3)
How can I write another function (somewhere else) that calls the feed function defined in the typeclass? Example:
feedEverything :: Bool
feedEverything = snd (feed Dog) == 0
Thanks
The problem is that Haskell can't figure out what type you want to use for food. It sees one instance:
instance AnimalTrainer Animal Food
But maybe there is a second instance somewhere...
instance AnimalTrainer Animal Poison
So you need to tell Haskell that animals get food only, and not something else like poison.
Solution 1: You can use functional dependencies:
class AnimalTrainer animal food | animal -> food where
...
This tells Haskell that for each animal type, there is only one food type that it will eat.
Solution 2: You can also use type families.
class AnimalTrainer animal where
type AnimalFood animal :: *
getFood :: animal -> (AnimalFood animal, Int)
feed :: animal -> (AnimalFood animal, Int)
feed a = feed' (getFood a) -- Provide a default implementation
where feed' (f, n) = (f, n - 1)
data Animal = Dog | Cat
data Food = Meat | Milk
instance AnimalTrainer Animal where
type AnimalFood Animal = Food
getFood Dog = (Meat, 2)
getFood Cat = (Milk, 3)
I personally consider this solution a little more esoteric, and the syntax a little less natural. But the example is contrived, so I include this for completeness.
Solution 3: You could add explicit type annotations whenever you call feed.
feedEverything = snd ((feed :: Animal -> (Food, Int)) Dog) == 0

Resources