IPiiro
IPiiro

Reputation: 97

How I can set the signature of a function right?

I'm practicing some Haskell to understand the \, case.. of and Maybe better.

I've got this little function here which should return Nothing if the array is empty, Just y if y is equal to the head of the array xs and Just (tail xs) if y is not equal to the head of the array xs.

I set the return type of the function to Maybe a because in one case it should return an Int and in the other an [Int].

funct :: Int -> [Int] ->  Maybe a
funct = \y xs -> case xs of
            [] -> Nothing
            xs -> if ((head xs) == y)
                        then Just y
                        else Just (tail xs)

What am I missing? I am getting the error that it couldn't match type a with [Int]. Isn't the a in Maybe a generic or is it influenced by the fact that I "used" the a as an Int in the Just y part?

EDIT: Ok my suggestion was bs, I tested it with Just (tail xs) in the then and else part and I'm still getting the same error.

Upvotes: 1

Views: 92

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477607

set the return type of the function to Maybe a because in one case it should return an Int and in the other an [Int].

Haskell is statically typed. Meaning it can not - at runtime - have a different return type. It can only have one return type. a is not an ad hoc type (in the sense that it can be any type at runtime). It means that a will be determined - at compile time - based on the types of other parameters.

For instance you can write: foo :: a -> a -> a to specify that if foo takes two Ints (again known at compile time), the result will be an Int.

You can however use Either a b to say that you will either return a Left a, or a Right b. So you can rewrite it to:

funct :: Int -> [Int] ->  Maybe (Either Int [Int])
funct = \y xs -> case xs of
            [] -> Nothing
            xs -> if ((head xs) == y)
                        then Just (Left y)
                        else Just (Right (tail xs))

Your function however is quite verbose, you can make it more clear and compact as follows:

funct :: Int -> [Int] ->  Maybe (Either Int [Int])
funct _ [] = Nothing
funct y (h:t) | h == y = Just (Left y)
              | otherwise = Just (Right t)

Furthermore we can generalize it to:

funct :: Eq a => a -> [a] ->  Maybe (Either a [a])
funct _ [] = Nothing
funct y (h:t) | h == y = Just (Left y)
              | otherwise = Just (Right t)

Here Eq is a typeclass that specifies that there exists a function (==) :: a -> a -> Bool that we can use. Otherwise using == in the body of the function would not be possible.

Furthermore we use patterns in the head of every clause. [] is a pattern that describes the empty list. (h:t) on the other hand is a pattern describing a list containing at least one element: the head h, followed by a (possibly empty tail t).

Upvotes: 6

Related Questions