Rank N types in let bindings - haskell

So I've done this...
{-# LANGUAGE Rank2Types, GADTs #-}
type Record fields = forall t. fields t -> t
data PersonField t where
Name :: PersonField String
Age :: PersonField Int
type Person = Record PersonField
And then this...
nigel :: Person
nigel Name = "Nigel"
nigel Age = 39
And it all seems to work as expected.
What I'm struggling with is how to define a Person value inside a let binding. For example this doesn't work:
abigail :: Person
abigail = let x Name = "Abigail"
x Age = 27
in x
Gives me:
Couldn't match expected type `t1' with actual type `[Char]'
`t1' is untouchable ...
Is there a way to make this work inside a let binding?

You need explicit type annotations when GADTs are involved:
abigail :: Person
abigail = let x :: Person
x Name = "Abigail"
x Age = 27
in x
Without it, GHC roughly sees
let x Name = "Abigail"
and says "OK, x is a function from the type of Name, i.e. PersonField String to the type of "Abigail", i.e. String. In the next line,
let x Name = "Abigail"
x Age = 27
GHC now finds out x to accept also a PersonField Int and to return a number. This clashes with the previously inferred type, triggering a type error.
With an explicit type annotation, type inference will not try to infer a wrong type for x: it was provided by the user. Instead, only type checking will be performed.

Related

Why can't haskell infer this type?

I have a simple type class that I'm having trouble working around.
class Entity a where
eid :: a -> b
data Item = Item
{ itemId :: Int
, itemName :: String
}
instance Entity Item where
eid i = itemId i
this gives me a compile error
main.hs:12:11: error:
* Couldn't match expected type `b' with actual type `Int'
`b' is a rigid type variable bound by
the type signature for:
eid :: forall b. Item -> b
at main.hs:12:3-5
* In the expression: itemId i
In an equation for `eid': eid i = itemId i
In the instance declaration for `Entity Item'
* Relevant bindings include
eid :: Item -> b (bound at main.hs:12:3)
|
12 | eid i = itemId i
| ^^^^^^^^
I would think the compiler would be smart enough to know that for an Item I would like eid to return the Int type based on the info I've given but, I'm obviously missing something.
I would think the compiler would be smart enough to know that for an Item I would like eid to return the Int type based on the info I've given but, I'm obviously missing something.
Your signature eid :: a -> b promises that it can return a value for every type b. So it is not the instance that will decide what the return type is, it is the usage of the eid function that will determine this. So it means that one can use this as eid :: Entity a => a -> Integer for example, not per se Int.
If b fully depends on a, you can make use of functional dependencies [haskell-wiki]:
{-# LANGUAGE FunctionalDependencies, MultiParamTypeClasses #-}
class Entity a b | a -> b where
eid :: a -> b
instance Entity Item Int where
eid = itemId
You can also drop the | a -> b part if for a given a, there can be multiple bs.
In Haskell it is not you who can decide what concrete type b stands for, but instead the caller of your eid function. By providing your implementation eid i = itemId i you fix the return type to be the same what itemId returns – an Int. Now the caller of eid can’t choose the type for b anymore, so this is why you get the error. It’s not really a lack of inference.
In a pure language the only thing a function can see is its arguments (and global constants). Here it is an a that is visible, but not a b. This means there exists no non-evil implementation for your function. Your function must return any type b that I (the caller) choose.
This signature won’t work, so you’ll have to change it. For example you could ask for the caller to provide a b and have eid :: a -> b -> b. In this case I am allowed to choose the type for b but I also have the obligation to provide you with a value of that type. Now your pure function can see a b and is able to return one.
Alternatively you could also simply specify that you want to return an Int: eid :: a -> Int.
Or you say: „Hey, I want to have a function that I provide with an a and I want it to compute any b a caller may choose – so let him provide me a function that can 'extract' that b”: eid :: a -> (a -> b) -> b.
Now the caller will have the obligation to pass in something like itemId. This means you have delayed the decision about what function actually can produce that b up until the point where eid is getting called.

What is the type keyword in Haskell

Stumbled on the type keyword in Haskell:
type Item = String
but not sure what it does, how to use it or how it is different from data. The online google search has been of no help.
I tried implementing it in a code like this:
import System.IO
main = do
putStrLn "Hello, what's your name?"
type Item = String
let test :: Item
test = "chris"
putStrLn test
but I got an error
parse error on input ‘type’
Please in a lay man's term what is type and how can it be used and how is it different from data?
It is a type alias. It means that you can use Item in your code where you can use String instead.
A type alias is often used when you for example want to give a name to more complex types. For example:
import Data.Map(Map)
type Dictionary = Map String String
here you thus can use Dictionary instead of each time writing Map String String.
It is furthermore often used if you want to specify that you are working with Items, the alias is then used in the type signature and in the documentation, which is often better than writing String.
It is also used if you do not yet know what type you will use for a specific object. By using a type alias, you can the work with Item, and later if you change your made define a type for Item or make it an alias of another type. This makes it more convenient to change the types.
I tried implementing it in a code like this:
import System.IO
main = do
putStrLn "Hello, what's your name?"
type Item = String
let test :: Item
test = "chris"
putStrLn test
A type alias is defined at the top level, so not in a do block, that would make a type definition locally scoped. While, like #moonGoose says, there are some proposals to make type definitions more locally scoped, currently it is not the case.
You can define the type alias like:
import System.IO
type Item = String
main = do
putStrLn "Hello, what's your name?"
let test :: Item
test = "chris"
putStrLn test
type A = B
means exactly the same as
typedef B A
in C or C++, and it behaves basically the same as simply
a = b
except that A and B are type-level entities, not value-level ones. For example
Prelude> type A = Int
Prelude> :i A
type A = Int -- Defined at <interactive>:1:1
Prelude> a = 37
Prelude> a
37
Because now A = Int, I can then use the type identifier A exactly everywhere I could also use Int directly:
Prelude> 37 :: Int
37
Prelude> 37 :: A
37
and even
Prelude> (37 :: Int) :: A
37
Note that there is no type conversion going on here, like you might have in other languages. Int and A are simply different names for the same type, so annotating with both is merely a tautology.
Contrast this with data (or newtype), which define a new, separate type which just happens to contain the, well, data of the specified type.
Prelude> data A' = A' { getA :: Int }
Prelude> (37 :: Int) :: A'
<interactive>:12:2: error:
• Couldn't match expected type ‘A'’ with actual type ‘Int’
• In the expression: (37 :: Int) :: A'
In an equation for ‘it’: it = (37 :: Int) :: A'

Silly duplicated record fields error

Consider the following:
{-# LANGUAGE DuplicateRecordFields #-}
data A = A { name :: String }
data B = B { name :: String }
main = print $ name (A "Alice")
When compiled, I get the following message (on GHC 8.0.2)
duplicatedrecords.hs:7:16: error:
Ambiguous occurrence ‘name’
It could refer to either the field ‘name’,
defined at duplicatedrecords.hs:5:14
or the field ‘name’, defined at duplicatedrecords.hs:3:14
But if I modify the main line as follows:
main = print $ name ((A "Alice") :: A)
Compilation proceeds successfully.
Why is this? The type signature :: A seems redundant to me, as surely the A constructor makes it clear to the compiler that (A "Alice") is of type A. But for some reason it makes a difference. Why is this and is there a way I can get this to compile without littering extra type signatures everywhere?
Note:
It's worth noting that the following compiles fine:
data A = A { a_name :: String }
data B = B { b_name :: String }
class Name t where
name :: t -> String
instance Name A where name = a_name
instance Name B where name = b_name
main = print $ name (A "Alice")
We can even go further as follows, allowing different result types:
{-# LANGUAGE TypeFamilies #-}
data A = A { a_name :: String }
data B = B { b_name :: Int }
class Name t where
type family T t
name :: t -> T t
instance Name A where
type T A = String
name = a_name
instance Name B where
type T B = Int
name = b_name
main = print $ name (A "Alice")
It seems like GHC just has to mechanically add a class for each unique record name and an instance for each record in each data type. This will mean however that name x == name y not implying that the types of x and y are the same but I'd expect that when using this extension anyway.
Just wondering if there's anything tricky I'm missing here regarding the implementation or that it just needs someone to do it?
-XDuplicateRecordFields currently doesn't infer types from arguments.
See GHC user guide section about this extension.
However, we do not infer the type of the argument to determine the datatype, or have any way of deferring the choice to the constraint solver. Thus the following is ambiguous:
But things are improving. So we might expect and finally get desired behavior:
https://prime.haskell.org/wiki/TypeDirectedNameResolution

Haskell - Type conversion?

I'm trying to convert data from a list, 'profile1', into a custom type called 'DataSubject'.
I'm passing this to a function 'makeDS' to attempt this conversion - however the following isn't working:
type Name = String
type Age = Int
type Iq = Int
type Language = String
data DataSubject = DS {name :: Name, age :: Age, iq :: Iq, language :: Language} deriving (Show)
data Contain = Name String | Age Int | Iq Int | Language String deriving (Show) --Use so list can take multiple types
profile1 = [Name "Bob", Age 22, Iq 100, Language "French"]
makeDS :: [Contain] -> DataSubject
makeDS t = DS {name = t!!0, age = t!!1, iq = t!!2, language = t!!3}
main = do
let x = makeDS profile1
putStrLn $ show x
Error:
Couldn't match type ‘Contain’ with ‘[Char]’
I'm just getting started with Haskell - could someone advise on my error? And if there's better ways of doing this?
In the definition of makeDS, the variable t is of type [Contain] (i.e. a list of Contain), so when you say t!!0 this will extract the first element of that list, which has type Contain. The problem is that the name field of DataSubject contains a String (which is an alias of [Char]). So you are trying to store a Contain in the place of [Char], which is not possible because the types are different. You need a different approach in you code.
One issue is that every single Contain value represents a single field of DataSubject. So if we are given a list of Contain, there is no guarantee that the values will be given in a specific order (e.g. Name first, followed by Age, etc) or even that all fields are provided. Even if you always provide all fields in a specific order in your code as convention, haskell cannot possibly know that. One solution that does not depend on order is to try to "build" the DataSubject object step-by-step, by starting with an "empty" DataSubject and then examining the list of Contain and adding the corresponding DataSubject field:
makeDS :: [Contain] -> DataSubject
makeDS = foldr updateDS emptyDS
where
updateDS (Name s) ds = ds {name = s}
updateDS (Age n) ds = ds {age = n}
updateDS (Iq n) ds = ds {iq = n}
updateDS (Language s) ds = ds {language = s}
emptyDS = DS {name = "", age = 0, iq = 0, language = ""}
So here, I defined emptyDS which is an "empty" DataSubject object and a function called updateDS which take a (single) Contain and a DataSubject and updates the DataSubject based on the field specified by Contain and then it returns it. Finally, I use a fold to run repeatedly update the DataSubject (starting with emptyDS) using updateDS.
You have a type mismatch. You have a list of Contain. So when you use
t !! 0
you get a Contain, not a String, which is necessary for name in DS. You need a function Contain -> Name, e.g.
containToName :: Contain -> Name
containToName (Name xs) = xs
containToName _ = error "not a name"
However, that's a partial function, since containToName (Age 12) will lead to an error.
Note that this has nothing to do with typeclasses. Now, if you want to use profile1, one way would be to just use
profile1 :: DataSubject
instead of
profile1 :: [Contain]
e.g.
profile1 :: DataSubject
profile1 = DS "Bob" 22 100 "French"
After all, there's nothing in the type [Contain] that will make sure that you have all the ingredients for a complete DataSubject.
And if there's better ways of doing this?
That depends on what you want to do. If you just want to handle DataSubjects, don't use an temporary list of Contain. If you want to handle user input (or similar), it gets a little bit more tricky.
The declaration of DataSubject says that we need a Name for the name field. And Name is the same as String. So in the expression DS {name = t!!0, ...}, we need t !! 0 to return a String. However, t !! 0 returns an element of t, and t has type [Contain]. So t !! 0 has type Contain, which is different from String.
To fix this type error, you need to convert the Contain to a String, maybe so:
DS { name = case t !! 0 of Name s => s, ... }

Writing A Function Polymorphic In A Type Family

I was experimenting with type families yesterday and ran into an obstacle with the following code:
{-# LANGUAGE TypeFamilies #-}
class C a where
type A a
myLength :: A a -> Int
instance C String where
type A String = [String]
myLength = length
instance C Int where
type A Int = [Int]
myLength = length
main = let a1 = [1,2,3]
a2 = ["hello","world"]
in print (myLength a1)
>> print (myLength a2)
Here I have a type associated with class C and a function that calculates the length of the associated type. However the above code gives me this error:
/tmp/type-families.hs:18:30:
Couldn't match type `A a1' with `[a]'
In the first argument of `myLength', namely `a1'
In the first argument of `print', namely `(myLength a1)'
In the first argument of `(>>)', namely `print (myLength a1)'
/tmp/type-families.hs:19:30:
Couldn't match type `A a2' with `[[Char]]'
In the first argument of `myLength', namely `a2'
In the first argument of `print', namely `(myLength a2)'
In the second argument of `(>>)', namely `print (myLength a2)'
Failed, modules loaded: none.
If, however I change "type" to "data" the code compiles and works:
{-# LANGUAGE TypeFamilies #-}
class C a where
data A a
myLength :: A a -> Int
instance C String where
data A String = S [String]
myLength (S a) = length a
instance C Int where
data A Int = I [Int]
myLength (I a) = length a
main = let a1 = I [1,2,3]
a2 = S ["hello","world"]
in
print (myLength a1) >>
print (myLength a2)
Why does "length" not work as expected in the first case? The lines "type A String ..." and "type A Int ..." specify that the type "A a" is a list so myLength should have the following types respectively : "myLength :: [String] -> Int" or "myLength :: [Int] -> Int".
Hm. Let's forget about types for a moment.
Let's say you have two functions:
import qualified Data.IntMap as IM
a :: Int -> Float
a x = fromInteger (x * x) / 2
l :: Int -> String
l x = fromMaybe "" $ IM.lookup x im
where im = IM.fromList -- etc...
Say there exists some value n :: Int that you care about. Given only the value of a n, how do you find the value of l n? You don't, of course.
How is this relevant? Well, the type of myLength is A a -> Int, where A a is the result of applying the "type function" A to some type a. However, myLength being part of a type class, the class parameter a is used to select which implementation of myLength to use. So, given a value of some specific type B, applying myLength to it gives a type of B -> Int, where B ~ A a and you need to know the a in order to look up the implementation of myLength. Given only the value of A a, how do you find the value of a? You don't, of course.
You could reasonably object that in your code here, the function A is invertible, unlike the a function in my earlier example. This is true, but the compiler can't do anything with that because of the open world assumption where type classes are involved; your module could, in theory, be imported by another module that defines its own instance, e.g.:
instance C Bool where
type A Bool = [String]
Silly? Yes. Valid code? Also yes.
In many cases, the use of constructors in Haskell serves to create trivially injective functions: The constructor introduces a new entity that is defined only and uniquely by the arguments it's given, making it simple to recover the original values. This is precisely the difference between the two versions of your code; the data family makes the type function invertible by defining a new, distinct type for each argument.

Resources