Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to print Nothing in Haskell

Tags:

haskell

I am trying to write a Haskell function that returns the first item in the list.

h [] = Nothing
h (x:xs) = x

When I call it with an empty list:

main = print (h [])

I got the following error:

prog.hs:4:8:
    No instance for (Show a0) arising from a use of `print'
    The type variable `a0' is ambiguous
    Possible fix: add a type signature that fixes these type variable(s)
    Note: there are several potential instances:
      instance Show Double -- Defined in `GHC.Float'
      instance Show Float -- Defined in `GHC.Float'
      instance (Integral a, Show a) => Show (GHC.Real.Ratio a)
        -- Defined in `GHC.Real'
      ...plus 23 others
    In the expression: print (h [])
    In an equation for `main': main = print (h [])

I want the result to be Nothing when I give the function the empty list.

like image 221
wannik Avatar asked Sep 17 '13 19:09

wannik


2 Answers

There are a few problems here, let's start by adding a reasonable type signature

h :: [a] -> Maybe a
h [] = Nothing
h (x:xs) = x

Now we get an error, we're returning a plain x so x needs to be of type Maybe a. We probably don't want this so we'll wrap it in the Just constructor

h (x:_) = Just x

Now on to your problem.

Notice that this isn't specific to your function, the result of

main = print $ head []
main = print $ id []
main = print $ tail []

are all the same.

The type of [] is [a]. Since we don't specify what a the type of h [] is Show a => Maybe a. The extra Show comes in because we want to print our result. But we don't actually say what a is so GHC freaks out being unable to default it.

There are two ways to fix it, the dumb way is to make h monomorphic (monomorphisize?) to h

h :: [Int] -> Maybe Int -- Bad

The smarter way is to simply choose a concrete type at our call site.

main = print $ h ([] :: [Int])

I chose Int for no particular reason, it doesn't matter that much. Now Maybe Int is printable so we're all set. The :: syntax works the same as it does for toplevel components, just declaring the type of [] in our expression is [Int].

Fun fact, GHCi has more aggressive defaulting than GHC. This means that

 main = print []

is legal in GHCi but not in GHC. If you're getting a funny behavior, ask for the type of the expression to see what the default is

 :t []
like image 181
Daniel Gratzer Avatar answered Oct 16 '22 17:10

Daniel Gratzer


Compiler eat silent your function

h [] = Nothing
h (x:xs) = x

but h has a type [Maybe a] -> Maybe a , not [a] -> Maybe a.

h :: [a] -> Maybe a
h [] = Nothing
h (x:_) = Just x

[] is polymorphic type [a], so the function result h [], equals Nothig is still polymorphic type Maybe a, but print can't work with polymorphic type (if we haven't instance of Show). In gchi you can run

> print (h [])

but this case gchi will transform it into print ((h []) :: Maybe Int)

But if you have less polymorphic function, like:

h [] = Nothing
h (x:_) = Just $ x == ""

then compiler find it type h :: [String] -> Maybe Bool and print (h []) work!

like image 39
viorior Avatar answered Oct 16 '22 15:10

viorior