Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are haskell type declarations used the same way as python class/function documentation?

I am using the "Learn you a haskell tutorial" and have reached the type declarations section. I understand that they change the way GHCI gives you an error message, but do they also affect the way the actual function works? If not, is it essentially like a python function documentation written with """ """ underneath "def someFunction(x): "? - just an example

Example code:

removeNonUppercase :: [Char] -> [Char]  
removeNonUppercase st = [ c | c <- st, c `elem` ['A'..'Z']]

EDIT: I ask this because the tutorial explains that haskell is type-inferred at compile time.

like image 442
Byte Avatar asked Dec 08 '22 02:12

Byte


1 Answers

Signatures aren't just for documentation (even though they are very useful for that as well). They are enforced by the compiler, which means that by adding signatures you can make the types of your functions more restrictive than they would be otherwise. Toy example:

add x y = x + y

addInt :: Int -> Int -> Int
addInt x y = x + y
*Main> :t add
add :: Num a => a -> a -> a
*Main> add 2 3
5
*Main> add 2.1 3.1
5.2
*Main> :t addInt
addInt :: Int -> Int -> Int
*Main> addInt 2 3
5
*Main> addInt 2.1 3.1 -- addInt will not accept non-Ints.

<interactive>:23:8:
    No instance for (Fractional Int) arising from the literal ‘2.1’
    In the first argument of ‘addInt’, namely ‘2.1’
    In the expression: addInt 2.1 3.1
    In an equation for ‘it’: it = addInt 2.1 3.1

Besides that, adding type signatures means you will get better (i.e. easier to understand) errors in tricky situations, as the compiler will know what you want to achieve rather than having to guess everything on its own.

There are also situations in which the compiler can't decide the types without the help of some signatures or other type annotations. Perhaps the simplest example is:

readAndShow s = show (read s)

If you try to use that without specifying any types...

Foo.hs:6:17:
    No instance for (Show a0) arising from a use of ‘show’
    The type variable ‘a0’ is ambiguous
    Note: there are several potential instances:
      instance (GHC.Arr.Ix a, Show a, Show b) => Show (GHC.Arr.Array a b)
        -- Defined in ‘GHC.Arr’
      instance Show a => Show (Maybe a) -- Defined in ‘GHC.Show’
      instance (Integral a, Show a) => Show (GHC.Real.Ratio a)
        -- Defined in ‘GHC.Real’
      ...plus 26 others
    In the expression: show (read s)
    In an equation for ‘readAndShow’: readAndShow s = show (read s)

Foo.hs:6:23:
    No instance for (Read a0) arising from a use of ‘read’
    The type variable ‘a0’ is ambiguous
    Note: there are several potential instances:
      instance (GHC.Arr.Ix a, Read a, Read b) => Read (GHC.Arr.Array a b)
        -- Defined in ‘GHC.Read’
      instance Read a => Read (Maybe a) -- Defined in ‘GHC.Read’
      instance (Integral a, Read a) => Read (GHC.Real.Ratio a)
        -- Defined in ‘GHC.Read’
      ...plus 25 others
    In the first argument of ‘show’, namely ‘(read s)’
    In the expression: show (read s)
    In an equation for ‘readAndShow’: readAndShow s = show (read s)
Failed, modules loaded: none.

... it won't work. read converts a String to some type, and show does the opposite. However, if nothing specifies the type of read s, the compiler can't tell which type you want to read the String as. So you either need to specify the intermediate type...

readAndShowAsInt s = show (read s :: Int)
*Main> readAndShowAsInt "2"
"2"

... Or have something else pick the type for you:

readAndAdd :: String -> Int -> Int
readAndAdd s y = read s + y
*Main> readAndAdd "2" 3
5
like image 55
duplode Avatar answered Dec 10 '22 15:12

duplode