4

I'm new to Haskell, and I'm trying to write a function that takes a list and returns a bool.

It will return True if its input list is the list consisting of 'a' only, and False otherwise.

This is my best guess:

f :: [a] -> Bool

f ('a':[]) = True

f (x:xs) = False

This fails to compile and returns:

Couldn't match type `a' with `Char'
  `a' is a rigid type variable bound by
      the type signature for f :: [a] -> Bool at charf.hs:6:1
In the pattern: 'b'
In the pattern: 'b' : []
In an equation for `f': f ('b' : []) = True

What is the error in my logic?

Ry-
  • 218,210
  • 55
  • 464
  • 476
user2666425
  • 1,671
  • 1
  • 15
  • 21
  • 2
    Do you mean the list should contain just one `Char` 'a'? In that case your function should have type `[Char] -> Bool`. At the moment the signature allows a list of any type, which is why you're getting the error. – Lee Aug 10 '13 at 18:04
  • Note that you can simply use `f x = x=="a"`, or even more concisely `f = (=="a")`. – leftaroundabout Aug 10 '13 at 19:13

3 Answers3

7
f :: [Char] -> Bool
f ['a'] = True
f _ = False

Use pattern matching. Your function doesn't seem to handle the empty list. Additionally, your function cannot be generic like you want because it clearly takes a [Char] (or a String).

Matt Bryant
  • 4,841
  • 4
  • 31
  • 46
  • [a] refers to lists of any type, right? So I can define a function that takes a list and returns true if the first element is 'a', false otherwise, or that was my goal at least. – user2666425 Aug 10 '13 at 18:07
  • You can't do that because you are explicitly using a `Char`. If you're trying to use an alpha list, you can't specify types anywhere in the signature. – Matt Bryant Aug 10 '13 at 18:09
  • Where am I explicitly using a char except in the defining equation? Why can't I use an alpha list and return true if head = 'a'? – user2666425 Aug 10 '13 at 18:19
  • Functions can only be of one type. Think of the alpha type as telling the compiler that it can generate functions for any type. When you use a char in the definition, you're breaking the ability to do that abstraction. – Matt Bryant Aug 10 '13 at 18:24
  • So then does that imply it isn't possible to do pattern matching if a function can take a list of any type? – user2666425 Aug 10 '13 at 18:26
  • It *might* be possible inside the function, but not in the definition. But you should definitely look this up; I'm by no means an expert in Haskell and can't give as good of an explanation as others. – Matt Bryant Aug 10 '13 at 18:37
  • If the function truly takes *any* type, then yes it's impossible to pattern match `fn :: a -> b` cannot be written, but something like `fn :: a -> (a -> b) -> b` can, it's clearly just `fn a f = f a`. Either case, you cannot pattern match on the `a`. However, you can write *your* function more polymorphically. Write `fn [a] = True; fn _ = False` and it'll be type `fn :: [a] -> Bool` which you can specialize to `fnChar = fn; fnChar :: [Char] -> Bool`. You end up pattern matching *only* on the `[]` part. – J. Abrahamson Aug 10 '13 at 19:13
  • Thank you all for the help. I don't think this is worth posting a new question, but the type declaration for `map` is: `map :: (a -> b) -> [a] -> [b]`. Why is `b` used here at all, and not `a` again? It doesn't return a distinct type `b`, but the type `a` = type `b`. I.e., map toUpper "cat", takes a string, and returns a string, not two different types. – user2666425 Aug 10 '13 at 19:18
  • 1
    In the example of map, `a` can be the same type as `b`, but is not necessarily. Consider `map (const True) "foo"`. If `map :: (a -> a) -> [a] -> [a]`, then you could indeed only produce lists of the same type as the original list. – Sarah Aug 10 '13 at 19:32
  • 3
    @user2666425 You can pattern match on generic lists. You just can't assume anything about the element type. When you put single quotes around your `a`, you're saying that the list must match a `Char` whose value is the character `'a'`. If you remove the quotes then that `a` will be a variable that will match any type and your function will work on arbitrary lists. – Gabriella Gonzalez Aug 10 '13 at 22:24
  • 1
    @user2666425 I think you have a misconception about how type variables work in Haskell. The type `[a]` doesn't mean "a list, each element of which can be a value from any type" but rather "a list whose elements are all values from one single type, which can by any type". Thus when you're processing that list, the only things you can do with the elements are things which are valid to do on *any* value from any type. Only `Char` values can be pattern matched against `'a'`, so you can't match against that pattern (or any other pattern at all, in fact). – Ben Aug 11 '13 at 01:20
1

If you want to create a function to test if a list contains a single given value, you need to make some changes.

Firstly you need to provide the expected value to compare against. At the moment you are trying to compare against the Char 'a', but you can't compare a Char to some unknown type a. Secondly, this type needs to be an instance of the Eq class so you can do the comparison.

You can pattern match against a singleton list, and then add a clause to compare the element with the one you expect e.g.

isSingletonOf :: Eq a => a -> [a] -> Bool
isSingletonOf v [s] | v == s = True
isSingletonOf _ _ = False

Then you can create a function to compare [Char]:

f :: [Char] -> Bool
f = isSingletonOf 'a'
Lee
  • 142,018
  • 20
  • 234
  • 287
0

You could also use the function elem, defined in Data.List, to do that.

Here is the documentation link:
http://hackage.haskell.org/packages/archive/base/latest/doc/html/Data-List.html#v:elem
(if you want to see how it is implemented you can click on source at the end of the line)

f :: [Char] -> Bool
f = elem 'a'

Concerning your answer regarding the type of map. As you said:
map :: (a -> b) -> [a] -> [b]
and
toUpper :: Char -> Char

consequently
map toUpper :: [Char] -> [Char]

if you were to define a function g :: String -> Int then
map g :: [String] -> [Int]
as you see, depending on the function you give as the first argument of map the resulting function may or may not have the same type in input and output.

Daiwen
  • 727
  • 1
  • 4
  • 15