Omar Shehab
Omar Shehab

Reputation: 1092

How to use these functions for a 'List' type

I am trying to understand how to use the functions defined in the following Haskell code (available here) in Prelude.

module List
    where

data List a = Nil
            | Cons a (List a)

listLength :: List a -> Int
listLength Nil = 0
listLength (Cons x xs) = 1 + listLength xs

{-
listHead :: List a -> Maybe a
listHead Nil = Nothing
listHead (Cons x xs) = Just x

listTail :: List a -> Maybe (List a)
listTail Nil = Nothing
listTail (Cons x xs) = Just xs
-}
listHead :: List a -> a
listHead (Cons x xs) = x

listTail :: List a -> List a
listTail (Cons x xs) = xs

listFoldl :: (a -> b -> a) -> a -> List b -> a
listFoldl f c Nil = c
listFoldl f c (Cons x xs) = listFoldl f (f c x) xs

listFoldr :: (a -> b -> b) -> b -> List a -> b
listFoldr f c Nil = c
listFoldr f c (Cons x xs) = f x (listFoldr f c xs)

I have loaded it using ghci List.hs command.

Then following is the way I am trying to use listHead.

*List> listHead (List 1:2:[])

<interactive>:7:11: Not in scope: data constructor `List'

Or like the following:

*List> listHead ('a':'b':[])

<interactive>:11:11:
    Couldn't match expected type `List a0' with actual type `[Char]'
    In the first argument of `listHead', namely `('a' : 'b' : [])'
    In the expression: listHead ('a' : 'b' : [])
    In an equation for `it': it = listHead ('a' : 'b' : [])

Could anyone please explain how to use this code in ghci? Thanks!

Upvotes: 0

Views: 105

Answers (2)

leftaroundabout
leftaroundabout

Reputation: 120751

The : operator and the [] construct are specific to Haskell's built-in list type, i.e. you can only use them to construct values of some type [a]. But the functions you have here don't deal with this standard list type, but with the locally defined List container. To construct such lists, you need to replace each : with Cons and each [] with Nil. It's complicated a bit by the fact that Cons is not an infix operator, so you first need to rewrite a:b as (:) a b. For example, the [Int] list 1:2:[] becomes (:) 1 ((:) 2 []), and that is equivalent to Cons 1 (Cons 2 Nil).

Those custom-lists can then be fed to any of those functions.

*List> listHead $ Cons 1 (Cons 2 Nil)
1

Of course this is ugly, but that List type is only introduced for educational purposes. In practice, you would use the standard [] type, or use nicer constructors. For instance, you can define infix constructors like : yourself:

infixr 6 :&
data List' a = N | a :& List' a

With that you could just do

*List> list'Head $ 1 :& 2 :& N

Alternatively, you could make GHC accept the [] syntax for your custom list type:

{-# LANGUAGE OverloadedLists, TypeFamilies #-}

import GHC.Exts (IsList(..))

instance  IsList (List l) where
  type Item (List l) = l
  fromList [] = Nil
  fromList (a:l) = Cons a $ fromList l

And then

*List> listHead [1,2]
1

Upvotes: 3

duplode
duplode

Reputation: 34398

You are supposed to build your custom Lists using the Cons and Nil data constructors that are defined by:

data List a = Nil
            | Cons a (List a)

The first error, Not in scope: data constructor `List', happened because you can't use List to build values (List is a type constructor, and List a is a type). What you actually want is:

listHead (Cons 1 (Cons 2 Nil)))

The second error, Couldn't match expected type `List a0' with actual type `[Char]', happened because you are trying to use the regular list constructors, (:) and [], to build List Char values. You should use Cons instead of (:) and Nil instead of [].

Upvotes: 2

Related Questions