Why is this feature not working?

Why not extractEither typecheck?

 data MyEither ab = MyLeft a | MyRight b deriving (Read, Show) extractEither :: MyEither ab -> 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 ab -> c at /Users/tongmuchenxuan/playground/test.hs:5:1 `c' is a rigid type variable bound by the type signature for extractEither :: MyEither ab -> c at /Users/tongmuchenxuan/playground/test.hs:5:1 In the expression: p In an equation for `extractEither': extractEither (MyLeft p) = p 

Is `c 'enough to catch any type?

+4
source share
4 answers

Not. c is any type that the caller may wish to return a function, i.e. for the function f :: a -> c , it would always be necessary to write fx + 1 :: Int , as well as putStr $ fx , as well as main = fx . Of course, your function does not allow it.

You want to return a dynamic type. Haskell intentionally does not allow this to be as easy as some other languages ​​do, as it can obviously lead to runtime errors when the return type is unexpected. There are various ways to do this, but this is the right option, depending on what you really want it on. Could you give some kind of context? Probably the best solution to your problem is not to use dynamic types, but something more Haskell-idiomatic.

Maybe you just want

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

which requires the types on both sides to be the same.

+12
source

Basically, your type signature says that your function can return a value of any type c given MyEither ab , again, for all a and b . However, as the compiler points out, it is impossible to create such a c here, since you are actually returning a value of type a (being p :: a ).

In addition, your definition still does not control the case when your MyEither ab not Left a . What to do, for example, when calling extractEither (MyRight 1) ? If you try to run such a function (after correcting the typical signature, of course), you may encounter what is called the exclusion pattern exception, which means that there is no body definition for extractEither to identify possible input patterns.

If you are trying to write a single function that works to extract both MyRight and MyRight , I'm afraid you should change your mind. To extract anything you want, left or right, you must have the same type on both sides (i.e. MyEither aa ), which is not so useful.

You must have functions to retrieve values. Here I return Maybe to avoid the burden of managing error calls, for example, when you try to extract the left from the correct value:

 extractMyLeft :: MyEither ab -> Maybe a extractMyRight :: MyEither ab -> Maybe b 

edit: see also dblhelix answer for a suggestion for another possible refactoring that might be useful for almost getting the type signature you were looking for.

+11
source

In addition to Riccardo, answer: if you want a function that can extract a value of some type c from a MyEither value whether it is built using MyLeft or MyRight , you can, instead of requiring the value to be of type MyEither cc , β€œinstruct” the function on how to get the value of c from either side:

 extractEither :: (a -> c) -> (b -> c) -> MyEither ab -> c extractEither fg (MyLeft x) = fx extractEither fg (MyRight y) = gy 

That is, extractEither now takes two additional arguments f and g : functions that are used to extract the extracted values ​​into values ​​of the required type.

This is a very common and useful idiom when working with amount types.

+8
source
 extractEither :: MyEither ab -> c extractEither (MyLeft p) = p 

Is `c 'enough to catch any type?

The intuition you bring to the table works in object-oriented languages ​​or in other languages ​​with subtyping, but not in Haskell or other parametric typing systems (for example, Java generic). Take this method signature in Java:

 public Object blah(Foo whatever); 

This method returns Object , which is the highest type in the hierarchy. This means that the implementation of this method can choose to return any type that it wants, and it will trivially rise to Object .

Haskell types do not work like this. You think your extractFilter might just return p because you implicitly assume that you , the author of extractEither , choose the type to use for c , just as the author of blah gets the choice of runtime type. But in Haskell it's the other way around: the caller of your function gets a choice of types for a , b and c , and they can choose the incompatible a and c . If I select any a β‰  c , there will be no final piece of code that you can write to turn my arbitrary choice of a into my arbitrary choice of c .

+1
source

All Articles