Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't this function signature typecheck?

Why doesn't extractEither typecheck?

data MyEither a b = MyLeft a | MyRight b
                    deriving (Read, Show)

extractEither :: MyEither a b -> c
extractEither (MyLeft p) = p

The compiler shows:

Couldn't match type `a' with `c'
  `a' is a rigid type variable bound by
      the type signature for extractEither :: MyEither a b -> c
      at /Users/tongmuchenxuan/playground/test.hs:5:1
  `c' is a rigid type variable bound by
      the type signature for extractEither :: MyEither a b -> c
      at /Users/tongmuchenxuan/playground/test.hs:5:1
In the expression: p
In an equation for `extractEither': extractEither (MyLeft p) = p

Isn't `c' general enough to catch any type?

like image 796
M. Tong Avatar asked Nov 27 '22 06:11

M. Tong


1 Answers

No. c is any type the caller could wish the function to return, i.e. for a function f :: a -> c it would always need to be possible to write f x + 1 :: Int as well as putStr $ f x as well as main = f x. Which your function does of course not permit.

What you want is returning a dynamic type. Haskell deliberately does not permit this as easily as some other languages do, because it obviously can lead to runtime errors easily when the returned type is something unexpected. There are various ways to do it, but which is the right one depends on what you actually want this for. Could you give some context? It's likely that the best solution to your problem would not use dynamic types, but something more Haskell-idiomatic.

Perhaps what you want is simply

extractEither :: MyEither a a -> a
extractEither (MyLeft p) = p
extractEither (MyRight p) = p

which requires that the types on both "sides" are the same.

like image 150
leftaroundabout Avatar answered Dec 05 '22 03:12

leftaroundabout