Ferry
Ferry

Reputation: 583

Haskell - Numbers and list

I've written following codes:

class Number a where
compareN :: [a] -> [(String,String,Int)]

type Name = String
type Nr = Int
data N = Nums Name Nr

compareNum :: N -> N -> Int
compareNum (Nums a b) (Nums c d) = abs(b-d) 

nameOfNum :: N -> String
nameOfNum (Nums a b) = a 

instance Number N where
    compareN [] = []
    compareN [nr] = [(a,b,c) | a <- [nameOfNum nr], b <- [nameOfNum nr], c <- [compareNum nr nr]]

When I try to run with:

    compareN [(Nums "one" 1),(Nums "two" 2)]

I got error msg: * Exception: test.hs:(18,9)-(19,101): Non-exhaustive patterns in function compareN

The anwser I want to get is like this:

[("one","one",0),("one","two",1),("two","one",1),("two","two",0)]

I know I have to write one more pattern:

compareN (nr:nrs) = [(a,b,c) | a <- [nameOfNum nr], b <- [nameOfNum nr], c <- [compareNum nr nr] : (compareN nrs)]

But it's not working.. Any help pls! Thx

Upvotes: 2

Views: 142

Answers (2)

KQ.
KQ.

Reputation: 922

The [] operator is a Data constructor for an empty list. A variable is needed for a non-empty list but that variable should not use the [..] list notation.

instance Number N where
    compareN [] = []
    compareN nr = ...

in this case, nr matches any non-empty list of one or more elements. You could use this if you don't care how many elements are in your list (excluding the empty list that your previous pattern matched).

Your intuition that you need:

compareN (n:nr) = ...

uses the other data constructor for a list, the ':' which prepends (lisp cons) an element to an existing list. This typically indicates you care whether or not your list has one or more than one elements, so if you need to differentiate in this way, you would write:

instance Number N where
    compareN [] = []
    compareN (nr:[]) = ...
    compareN (n:nr) = ...

The second will match a list element preceeding an empty list (a list of one element) whereas the third will match anything else and return you n as the first element and nr as any remaining elements.

You can use the first form above if you only care about empty v.s. non-empty, or the second form if you care about empty, single-entry, and multiple entries.

Upvotes: 4

fuz
fuz

Reputation: 93082

You use pattern matching as if you tried to do a manual recursion, but in the same moment you do a strange list comprehension. Here is a cleaner approach. The first step generates all permutations of the two numbers and the second does the comparisons:

compareN xs = [(a,b,compareNum a b) | a <- xs, b <- xs]

The syntax a <- xs, b <- xs means, that the output consists of all possible ways to take an a and a b from xs; no pattern matching is needed here.

Upvotes: 4

Related Questions