How to write getters for existential types in Haskell - haskell

Thanks to the answer to this question I've defined a type like so:
data Chain = forall a. Integral a => Chain [[a]] [a] a a
I need to write a getter function for each field, or argument if you like. Here's my first attempt:
getSimplices (Chain simplices _ _ _) = simplices
But when I try to compile ghc gives the following error:
Chain.hs:10:40: error:
• Couldn't match expected type ‘t’ with actual type ‘[[a]]’
because type variable ‘a’ would escape its scope
This (rigid, skolem) type variable is bound by
a pattern with constructor:
Chain :: forall a. Integral a => [[a]] -> [a] -> a -> a -> Chain,
in an equation for ‘getSimplices’
at Chain.hs:10:15-35
• In the expression: simplices
In an equation for ‘getSimplices’:
getSimplices (Chain simplices _ _ _) = simplices
• Relevant bindings include
simplices :: [[a]] (bound at Chain.hs:10:21)
getSimplices :: Chain -> t (bound at Chain.hs:10:1)
I fixed it like this:
getSimplices (Chain simplices _ _ _) = map (map fromIntegral) simplices
Even if some kind of ghc magic prevents this from being obscenely slow for a getter, I think fixing something this way is just atrocious. Is there a better way to define getters for types like this?

The constructor of an existential type necessarily "forgets" about a:
Chain :: Integral a => [[a]] -> [[a]] -> a -> a -> Chain
Note how the resulting type no longer depends on a.
A consequence of this is that, when we pattern match on Chain, we can not make any assumption about what a is. After all we could have chosen anything when constructing. The only knowledge we have on a is that it must be an integral type. Hence, we can only access using the methods of the Integral type class.
The general rule is that, when we pattern match on Chain, we must return a value of a type which does not depend on a. A getter like
getter (Chain _ _ x _) = x
violate that rule. After all, what type would that have?
getter :: Chain -> ???
Surely not
getter :: Chain -> a
which would instead mean that we can extract any type we wish from Chain. This can not realistically work: we can't be free to choose what type to put in, and then be also free to choose what type to take out.
What we can do, however, is to exploit Integral:
getter :: Chain -> Integer
getter (Chain _ _ x _) = fromIntegral x
Integer does not depend on a, so it is OK.

What type do you suppose getSimplices should have? The "obvious" choice is
getSimplices :: Integral a => Chain -> [[a]]
But this doesn't work with your implementation, because the caller of getSimplices gets to choose the a, and there's no guarantee that the values stored in the Chain are of the same type that the caller wants, since you threw that information away. Consider:
let c = Chain [[1 :: Int]] [2] 3 4
in (getSimplices c) :: [[Integer]]
This is clearly allowed by your two type signatures which promise to work for any Integral type, but also clearly cannot work without some conversion: the Ints have to be turned into Integers somehow.
As the comments say, this is rather unusual. It would be much simpler to add a type parameter to Chain, so that it tracks the type you used to create it, and constrains its output to that type as well:
data Chain a = Chain [[a]] [a] a a
getSimplices :: Chain a -> [[a]]
getSimplices (Chain xs _ _ _) = xs

Related

Confused about GADTs and propagating constraints

There's plenty of Q&A about GADTs being better than DatatypeContexts, because GADTs automagically make constraints available in the right places. For example here, here, here. But sometimes it seems I still need an explicit constraint. What's going on? Example adapted from this answer:
{-# LANGUAGE GADTs #-}
import Data.Maybe -- fromJust
data GADTBag a where
MkGADTBag :: Eq a => { unGADTBag :: [a] } -> GADTBag a
baz (MkGADTBag x) (Just y) = x == y
baz2 x y = unGADTBag x == fromJust y
-- unGADTBag :: GADTBag a -> [a] -- inferred, no Eq a
-- baz :: GADTBag a -> Maybe [a] -> Bool -- inferred, no Eq a
-- baz2 :: Eq a => GADTBag a -> Maybe [a] -> Bool -- inferred, with Eq a
Why can't the type for unGADTBag tell us Eq a?
baz and baz2 are morally equivalent, yet have different types. Presumably because unGADTBag has no Eq a, then the constraint can't propagate into any code using unGADTBag.
But with baz2 there's an Eq a constraint hiding inside the GADTBag a. Presumably baz2's Eq a will want a duplicate of the dictionary already there(?)
Is it that potentially a GADT might have many data constructors, each with different (or no) constraints? That's not the case here, or with typical examples for constrained data structures like Bags, Sets, Ordered Lists.
The equivalent for a GADTBag datatype using DatatypeContexts infers baz's type same as baz2.
Bonus question: why can't I get an ordinary ... deriving (Eq) for GADTBag? I can get one with StandaloneDeriving, but it's blimmin obvious, why can't GHC just do it for me?
deriving instance (Eq a) => Eq (GADTBag a)
Is the problem again that there might be other data constructors?
(Code exercised at GHC 8.6.5, if that's relevant.)
Addit: in light of #chi's and #leftroundabout's answers -- neither of which I find convincing. All of these give *** Exception: Prelude.undefined:
*DTContexts> unGADTBag undefined
*DTContexts> unGADTBag $ MkGADTBag undefined
*DTContexts> unGADTBag $ MkGADTBag (undefined :: String)
*DTContexts> unGADTBag $ MkGADTBag (undefined :: [a])
*DTContexts> baz undefined (Just "hello")
*DTContexts> baz (MkGADTBag undefined) (Just "hello")
*DTContexts> baz (MkGADTBag (undefined :: String)) (Just "hello")
*DTContexts> baz2 undefined (Just "hello")
*DTContexts> baz2 (MkGADTBag undefined) (Just "hello")
*DTContexts> baz2 (MkGADTBag (undefined :: String)) (Just "hello")
Whereas these two give the same type error at compile time * Couldn't match expected type ``[Char]'* No instance for (Eq (Int -> Int)) arising from a use of ``MkGADTBag'/ ``baz2' respectively [Edit: my initial Addit gave the wrong expression and wrong error message]:
*DTContexts> baz (MkGADTBag (undefined :: [Int -> Int])) (Just [(+ 1)])
*DTContexts> baz2 (MkGADTBag (undefined :: [Int -> Int])) (Just [(+ 1)])
So baz, baz2 are morally equivalent not just in that they return the same result for the same well-defined arguments; but also in that they exhibit the same behaviour for the same ill-defined arguments. Or they differ only in where the absence of an Eq instance gets reported?
#leftroundabout Before you've actually deconstructed the x value, there's no way of knowing that the MkGADTBag constructor indeed applies.
Yes there is: field label unGADTBag is defined if and only if there's a pattern match on MkGADTBag. (It would maybe be different if there were other constructors for the type -- especially if those also had a label unGADTBag.) Again, being undefined/lazy evaluation doesn't postpone the type-inference.
To be clear, by "[not] convincing" I mean: I can see the behaviour and the inferred types I'm getting. I don't see that laziness or potential undefinedness gets in the way of type inference. How could I expose a difference between baz, baz2 that would explain why they have different types?
Function calls never bring type class constraints in scope, only (strict) pattern matching does.
The comparison
unGADTBag x == fromJust y
is essentially a function call of the form
foo (unGADTBag x) (fromJust y)
where foo requires Eq a. That would morally be provided by unGADTBag x, but that expression is not yet evaluated! Because of laziness, unGADTBag x will be evaluated only when (and if) foo demands its first argument.
So, in order to call foo in this example we need its argument to be evaluated in advance. While Haskell could work like this, it would be a rather surprising semantics, where arguments are evaluated or not depending on whether they provide a type class constraint which is needed. Imagine more general cases like
foo (if cond then unGADTBag x else unGADTBag z) (fromJust y)
What should be evaluated here? unGADTBag x? unGADTBag y? Both? cond as well? It's hard to tell.
Because of these issues, Haskell was designed so that we need to manually require the evaluation of a GADT value like x using pattern matching.
Why can't the type for unGADTBag tell us Eq a?
Before you've actually deconstructed the x value, there's no way of knowing that the MkGADTBag constructor indeed applies. Sure, if it doesn't then you have other problems (bottom), but those might conceivably not surface. Consider
ignore :: a -> b -> b
ignore _ = id
baz2' :: GADTBag a -> Maybe [a] -> Bool
baz2' x y = ignore (unGADTBag x) (y==y)
Note that I could now invoke the function with, say, undefined :: GADTBag (Int->Int). Shouldn't be a problem since the undefined is ignored, right★? Problem is, despite Int->Int not having an Eq instance, I was able to write y==y, which y :: Maybe [Int->Int] can't in fact support.
So, we can't have that only mentioning unGADTBag is enough to spew the Eq a constraint into its surrounding scope. Instead, we must clearly delimit the scope of that constraint to where we've confirmed that the MkGADTBag constructor does apply, and a pattern match accomplishes that.
★If you're annoyed that my argument relies on undefined, note that the same issue arises also when there are multiple constructors which would bring different constraints into scope.
An alternative to a pattern-match that does work is this:
{-# LANGUAGE RankNTypes #-}
withGADTBag :: GADTBag a -> (Eq a => [a] -> b) -> b
withGADTBag (MkGADTBag x) f = f x
baz3 :: GADTBag a -> Maybe [a] -> Bool
baz3 x y = withGADTBag x (== fromJust y)
Response to edits
All of these give *** Exception: Prelude.undefined:
Yes of course they do, because you actually evaluate x == y in your function. So the function can only possibly yield non-⟂ if the inputs have a NF. But that's by no means the case for all functions.
Whereas these two give the same type error at compile time
Of course they do, because you're trying to wrap a value of non-Eq type in the MkGADTBag constructor, which explicitly requires that constraint (and allows you to explicitly unwrap it again!), whereas the GADTBag type doesn't require that constraint. (Which is kind of the whole point about this sort of encapsulation!)
Before you've actually deconstructed the x value, there's no way of knowing that the `MkGADTBag` constructor indeed applies.Yes there is: field label `unGADTBag` is defined if and only if there's a pattern match on `MkGADTBag`.
Arguably, that's the way field labels should work, but they don't, in Haskell. A field label is nothing but a function from the data type to the field type, and a nontotal function at that if there are multiple constructors.Yeah, Haskell records are one of the worst-designed features of the language. I personally tend to use field labels only for big, single-constructor, plain-old-data types (and even then I prefer using not the field labels directly but lenses derived from them).
Anyway though, I don't see how “field label is defined iff there's a pattern match” could even be implemented in a way that would allow your code to work the way you think it should. The compiler would have to insert the step of confirming that the constructor applies (and extracting its GADT-encapsulated constraint) somewhere. But where? In your example it's reasonably obvious, but in general x could inhabit a vast scope with lots of decision branches and you really don't want it to get evaluated in a branch where the constraint isn't actually needed.
Also keep in mind that when we argue with undefined/⟂ it's not just about actually diverging computations, more typically you're worried about computations that would simply take a long time (just, Haskell doesn't actually have a notion of “taking a long time”).
The way to think about this is OutsideIn(X) ... with local assumptions. It's not about undefinedness or lazy evaluation. A pattern match on a GADT constructor is outside, the RHS of the equation is inside. Constraints from the constructor are made available only locally -- that is only inside.
baz (MkGADTBag x) (Just y) = x == y
Has an explicit data constructor MkGADTBag outside, supplying an Eq a. The x == y raises a wanted Eq a locally/inside, which gets discharged from the pattern match. OTOH
baz2 x y = unGADTBag x == fromJust y
Has no explicit data constructor outside, so no context is supplied. unGADTBag has a Eq a, but that is deeper inside the l.h. argument to ==; type inference doesn't go looking deeper inside. It just doesn't. Then in the effective definition for unGADTBag
unGADTBag (MkGADTBag x) = x
there is an Eq a made available from the outside, but it cannot escape from the RHS into the type environment at a usage site for unGADTBag. It just doesn't. Sad!
The best I can see for an explanation is towards the end of the OutsideIn paper, Section 9.7 Is the emphasis on principal types well-justified? (A rhetorical question but my answer would me: of course we must emphasise principal types; type inference could get better principaled under some circumstances.) That last section considers this example
data R a where
RInt :: Int -> R Int
RBool :: Bool -> R Bool
RChar :: Char -> R Char
flop1 (RInt x) = x
there is a third type that is arguably more desirable [for flop1], and that type is R Int -> Int.
flop1's definition is of the same form as unGADTBag, with a constrained to be Int.
flop2 (RInt x) = x
flop2 (RBool x) = x
Unfortunately, ordinary polymorphic types are too weak to express this restriction [that a must be only Int or Bool] and we can only get Ɐa.R a -> a for flop2, which does not rule the application of flop2 to values of type R Char.
So at that point the paper seems to give up trying to refine better principal types:
In conclusion, giving up on some natural principal types in favor of more specialized types that eliminate more pattern match errors at runtime is appealing but does not quite work unless we consider a more expressive syntax of types. Furthermore it is far from obvious how to specify these typings in a high-level declarative specification.
"is appealing". It just doesn't.
I can see a general solution is difficult/impossible. But for use-cases of constrained Bags/Lists/Sets, the specification is:
All data constructors have the same constraint(s) on the datatype's parameters.
All constructors yield the same type (... -> T a or ... -> T [a] or ... -> T Int, etc).
Datatypes with a single constructor satisfy that trivially.
To satisfy the first bullet, for a Set type using a binary balanced tree, there'd be a non-obvious definition for the Nil constructor:
data OrdSet a where
SNode :: Ord a => OrdSet a -> a -> OrdSet a -> OrdSet a
SNil :: Ord a => OrdSet a -- seemingly redundant Ord constraint
Even so, repeating the constraint on every node and every terminal seems wasteful: it's the same constraint all the way down (which is unlike GADTs for EDSL abstract syntax trees); presumably each node carries a copy of exactly the same dictionary.
The best way to ensure same constraint(s) on every constructor could just be prefixing the constraint to the datatype:
data Ord a => OrdSet a where ...
And perhaps the constraint could go 'OutsideOut' to the environment that's accessing the tree.
Another possible approach is to use a PatternSynonym with an explicit signature giving a Required constraint.
pattern EqGADTBag :: Eq a => [a] -> GADTBag a -- that Eq a is the *Required*
pattern EqGADTBag{ unEqGADTBag } = MkGADTBag unEqGADTBag -- without sig infers Eq a only as *Provided*
That is, without that explicit sig:
*> :i EqGADTBag
pattern EqGADTBag :: () => Eq a => [a] -> GADTBag a
The () => Eq a => ... shows Eq a is Provided, arising from the GADT constructor.
Now we get both inferred baz, baz2 :: Eq a => GADTBag a -> Maybe [a] -> Bool:
baz (EqGADTBag x) (Just y) = x == y
baz2 x y = unEqGADTBag x == fromJust y
As a curiosity: it's possible to give those equations for baz, baz2 as well as those in the O.P. using the names from the GADT decl. GHC warns of overlapping patterns [correctly]; and does infer the constrained sig for baz.
I wonder if there's a design pattern here? Don't put constraints on the data constructor -- that is, don't make it a GADT. Instead declare a 'shadow' PatternSynonym with the Required/Provided constraints.
You can capture the constraint in a fold function, (Eq a => ..) says you can assume Eq a but only within the function next (which is defined after a pattern match). If you instantiate next as = fromJust maybe == as it uses this constraint to witness equality
-- local constraint
-- |
-- vvvvvvvvvvvvvvvvvv
foldGADTBag :: (Eq a => [a] -> res) -> GADTBag a -> res
foldGADTBag next (MkGADTBag as) = next as
baz3 :: GADTBag a -> Maybe [a] -> Bool
baz3 gadtBag maybe = foldGADTBag (fromJust maybe ==) gadtBag
type Ty :: Type -> Type
data Ty a where
TyInt :: Int -> Ty Int
TyUnit :: Ty ()
-- locally assume Int locally assume unit
-- | |
-- vvvvvvvvvvvvvvvvvvv vvvvvvvvvvvvv
foldTy :: (a ~ Int => a -> res) -> (a ~ () => res) -> (Ty a -> res)
foldTy int unit (TyInt i) = int i
foldTy int unit TyUnit = unit
eval :: Ty a -> a
eval = foldTy id ()

Type of any in Haskell?

I've recently started trying to learn Haskell by reading LearnYouAHaskell and random articles from the internet.
I'm having hard time understanding more sophisticated function types.
Some examples that I understand.
> :t map
map :: (a -> b) -> [a] -> [b]
It takes in a function (which takes a and gives out b, i.e a and b can be of different types) and a list of a's and return a list of b's.
> :t fst
fst :: (a, b) -> a
Takes in a tuple of 2 elements (allows different types) and returns the first one.
> :t any
At a higher level, I understand any. It takes in a function and a list and returns true if any of the list entries return true for that particular function. I've used it in Python and JavaScript as well.
Questions
I don't understand how does any :: Foldable t => (a -> Bool) -> t a -> Bool
translate to the above.
(a -> Bool) is the predicate. Takes in an argument and returns true or false.
t a -> Bool Bool is the end result of any. According to my understanding t and a represent the predicate and the list. Why aren't they separated by a ->
How to go about understanding type signatures in general and how to dig deeper so that I can approach them myself?
any :: Foldable t => (a -> Bool) -> t a -> Bool
Here Foldable t means, that t is an instance of type class Foldable.
Foldable is a type class and if type t is an instance of the type class Foldable we know from the t a part of the signature or from the definition of the type class Foldable, that t is actually a type constructor.
So t a is a type and therefore t a -> Bool is a function, that maps a value of type t a to Bool. This function will be closure, which will
apply the predicate to each "element" of the value of type t a, until it finds one, that yields True under the predicate or it doesn't find such an element returning either True or False in the respective cases. (The actual implementation might be very different.)
For example [] is an instance of the type class Foldable and therefore t a could be a list of something. In this case, we can also write [a] instead of [] a.
But there are other type constructors, which can be instances of Foldable, for example some kinds of trees.
It might be helpful to note that until recently, the signature was actually
any :: (a -> Bool) -> [a] -> Bool
This was generalised during the Foldable Traversable in Prelude proposal: now the container of values need not be a list, but can as well be e.g. an array:
Prelude> import qualified Data.Vector as Arr
Prelude Arr> :set -XOverloadedLists
Prelude Arr> let a = [1,2,3] :: Arr.Vector Int
Prelude Arr> any (>2) a
True
Type signature is a mark up designation of the function indicating the types to be processed and how the function can be partially applied.
Foldable t => (a -> Bool) -> t a -> Bool
By Foldable t it first says any function can work with any data type which is an instance of Foldable type class.
The first parameter, (a -> Bool) is obviously a function which takes a single element (a) from our foldable data type and returns a Bool type value. It's the the callback of .some(callback) in JavaScript. When you apply this parameter to any you will be returned with a function of type;
t a -> Bool
Now we are left with a single function which takes only one parameter and returns a Bool type (True or False) value. Again t a is a data type which is a member of the Foldable type class. It can be a [] but a Tree too provided that the data type has foldMap function defined under an instance to Foldable. It's the myArr part in JavaScript's myArr.some(callback) except that it doesn't have to be an array.
t a isn't separated by a -> because the t a is the instance of foldable, ex: List a, or Tree a. Let's go back to map for a second. The version you gave is specialized to lists; a more general version (which, as an accident of history, is called fmap in most versions of Haskell) has type fmap :: Functor f => (a->b) -> f a -> f b. Where is your input list in this signature? It's the f a. Now, returning to any the t a is the second argument, the instance of Foldable you're folding over, the list or tree or whatever.
You'll read that all functions in Haskell really have only 1 argument, and we're seeing that here. any takes it's first argument (the predicate) and returns a function that takes a foldable (the list, tree, etc) and returns a Bool.
t a does not represent the predicate and the list. As you've already correctly pointed out before, (a -> Bool) is the predicate. t a just represents the list, except it doesn't have to be a list (that's why it's t a instead of [a]). t can be any Foldable, so it could be [], but it could also be some other collection type or Maybe.

Why does the type of a function change when it comes out of a monad in GHCi [duplicate]

This question already has an answer here:
Why does `peek` with a polymorphic Ptr return GHC.Prim.Any when used with a bind?
(1 answer)
Closed 6 years ago.
Something changes about the type of a function when it comes out of a monad.
In GHCI:
> :t map
map :: (a -> b) -> [a] -> [b]
> a <- return map
> :t a
a :: (GHC.Prim.Any -> GHC.Prim.Any)
-> [GHC.Prim.Any] -> [GHC.Prim.Any]
This change makes it hard to store the function in a higher rank type.
What is happening here and can I make it not happen?
(Also doesn't this violate one of the monad laws?)
First of all, there is no point in doing anything like a <- return map - its the same as let a = map, which works just fine. That said, I don't think that is your question...
Checking out the documentation of GHC.Prim.Any which gives us a big hint as to the role of Any.
It's also used to instantiate un-constrained type variables after type
checking. For example, length has type
length :: forall a. [a] -> Int
and the list datacon for the empty list has type
[] :: forall a. [a]
In order to compose these two terms as length [] a
type application is required, but there is no constraint on the
choice. In this situation GHC uses Any
(In terms of type application syntax, that looks like length #Any ([] #Any *))
The problem is that when GHCi sees x <- return map it tries to desugar it to return map >>= \x -> ... but the ... part is whatever you enter next into GHCi. Normally it would figure out what the type variables of map are going to be instantiated to (or whether they even should be instantiated to anything) based the ..., but since it has nothing there.
Another key point that #sepp2k points out is that x can't be given a polymorphic type because (>>=) expects (on its RHS) a rank-1 function, and that means its argument can't be polymorphic. (Loosening this condition pushes you straight into RankNTypes at which point you lose the ability to infer types reliably.)
Therefore, needing x to be monomorphic and having no information to help it instantiate the type variables that prevent x from being monomorphic, it defaults to using Any. That means that instead of (a -> b) -> [a] -> [b] you get (Any -> Any) -> [Any] -> [Any].

How to create a base case for a tuple in Haskell?

I have the following function:
encode_single :: (Eq a) => [a] -> (Int, a)
encode_single (x:xs) = (count xs + 1, x)
However, Haskell complained about needing a base case, but I don't know how to do this because of the generic a type.
Thanks!
First of all, what you received is only a warning, not an error. Haskell does not need the base case of the empty list, it just suggests it.
Partial functions are most often an anti-pattern in functional programming so it just points out something that may be wrong. You can avoid the warning in different ways.
The first one is to make your function safe: if it cannot always return a value it's return type shouldn't be (Int, a) but Maybe (Int, a), so you could do:
encode_single :: (Eq a) => [a] -> Maybe (Int, a)
encode_single [] = Nothing
encode_single (x:xs) = Just (count xs + 1, x)
Otherwise you'd have to return a meaningful value for the empty case (just returning undefined isn't better than not defining that case). It might be appropriate to do somethign like:
encode_single [] = (0, undefined)
However this assumes that any code that uses the result of encode_single will not evaluate the second element of the tuple if the first element is zero (note that if the list isn't empty the first element is always positive, so 0 can be used as a sentinel value).
This may or may not be the case. However one thing is sure: this is not compile-time safe so you may receive some run-time errors when calling such a function.
Simply enough: at the type you desire you cannot write a total function of that specification. You need to change the type.
You can either add a default a or indicate partiality using Maybe.
encode_single :: a -> [a] -> (Int, a)
encode_single :: [a] -> Maybe (Int, a)
if you cannot change the type signature, you can piggyback on head i.e.
encode_single :: [a] -> (Int, a)
encode_single a = (length a, head a)
obviously, empty list input is not handled properly.

How to Interpret (Eq a)

I need to create a function of two parameters, an Int and a [Int], that returns a new [Int] with all occurrences of the first parameter removed.
I can create the function easily enough, both with list comprehension and list recursion. However, I do it with these parameters:
deleteAll_list_comp :: Integer -> [Integer] -> [Integer]
deleteAll_list_rec :: (Integer -> Bool) -> [Integer] -> [Integer]
For my assignment, however, my required parameters are
deleteAll_list_comp :: (Eq a) => a -> [a] -> [a]
deleteAll_list_rec :: (Eq a) => a -> [a] -> [a]
I don't know how to read this syntax. As Google has told me, (Eq a) merely explains to Haskell that a is a type that is comparable. However, I don't understand the point of this as all Ints are naturally comparable. How do I go about interpreting and implementing the methods using these parameters? What I mean is, what exactly are the parameters to begin with?
#groovy #pelotom
Thanks, this makes it very clear. I understand now that really it is only asking for two parameters as opposed to three. However, I still am running into a problem with this code.
deleteAll_list_rec :: (Eq a) => a -> [a] -> [a]
delete_list_rec toDelete [] = []
delete_list_rec toDelete (a:as) =
if(toDelete == a) then delete_list_rec toDelete as
else a:(delete_list_rec toDelete as)
This gives me a "The type signature for deleteAll_list_rec
lacks an accompanying binding" which makes no sense to me seeing as how I did bind the requirements properly, didn't I? From my small experience, (a:as) counts as a list while extracting the first element from it. Why does this generate an error but
deleteAll_list_comp :: (Eq a) => a -> [a] -> [a]
deleteAll_list_comp toDelete ls = [x | x <- ls, toDelete==x]
does not?
2/7/13 Update: For all those who might stumble upon this post in the future with the same question, I've found some good information about Haskell in general, and my question specifically, at this link : http://learnyouahaskell.com/types-and-typeclasses
"Interesting. We see a new thing here, the => symbol. Everything before the => symbol is >called a class constraint. We can read the previous type declaration like this: the >equality function takes any two values that are of the same type and returns a Bool. The >type of those two values must be a member of the Eq class (this was the class constraint).
The Eq typeclass provides an interface for testing for equality. Any type where it makes >sense to test for equality between two values of that type should be a member of the Eq >class. All standard Haskell types except for IO (the type for dealing with input and >output) and functions are a part of the Eq typeclass."
One way to think of the parameters could be:
(Eq a) => a -> [a] -> [a]
(Eq a) => means any a's in the function parameters should be members of the
class Eq, which can be evaluated as equal or unequal.*
a -> [a] means the function will have two parameters: (1) an element of
type a, and (2) a list of elements of the same type a (we know that
type a in this case should be a member of class Eq, such as Num or
String).
-> [a] means the function will return a list of elements of the same
type a; and the assignment states that this returned list should
exclude any elements that equal the first function parameter,
toDelete.
(* edited based on pelotom's comment)
What you implemented (rather, what you think you implemented) is a function that works only on lists of Integers, what the assignment wants you to do is create one that works on lists of all types provided they are equality-comparable (so that your function will also work on lists of booleans or strings). You probably don't have to change a lot: Try removing the explicit type signatures from your code and ask ghci about the type that it would infer from your code (:l yourfile.hs and then :t deleteAll_list_comp). Unless you use arithmetic operations or similar things, you will most likely find that your functions already work for all Eq a.
As a simpler example that may explain the concept: Let's say we want to write a function isequal that checks for equality (slightly useless, but hey):
isequal :: Integer -> Integer -> Bool
isequal a b = (a == b)
This is a perfectly fine definition of isequal, but the type constraints that I have manually put on it are way stronger than they have to. In fact, in the absence of the manual type signature, ghci infers:
Prelude> :t isequal
isequal :: Eq a => a -> a -> Bool
which tells us that the function will work for all input types, as long as they are deriving Eq, which means nothing more than having a proper == relation defined on them.
There is still a problem with your _rec function though, since it should do the same thing as your _comp function, the type signatures should match.

Resources