haskellarguments

Haskell function with data pattern match and second argument gives Equations have different numbers of arguments


In Haskell I have the following data structure

data Circ = IN String
    | NOT Circ
    | AND Circ Circ
    | OR Circ Circ
    | XOR Circ Circ

I can pattern match functions on this like so:

size :: Circ -> Int
size (IN _) = 0
..
size (XOR a b) = 1 + (size a) + (size b)

but when I try this with an additional argument:

simulate :: Circ -> [(String, Bool)] -> Bool
simulate (IN a) c = findIn c a
simulate (NOT a) c = not $ simulate a c
simulate (AND a b) c = all (simulate a c) (simulate b c)
simulate (OR a b) c = any (simulate a c) (simulate b c)
simulate (XOR a b) = xor (simulate a c) (simulate b c)

I get the error Equations for ‘simulate’ have different numbers of arguments. How can I write a function that pattern matches a data structure with extra arguments?

I tried rewriting the brackets and couldn't find anything about this online.

I expect it to put the values of the data structure in some of the arguments and receive the next argument alongside it.

Thanks in advance!


Solution

  • This is caused by the missing c in the last clause:

    simulate :: Circ -> [(String, Bool)] -> Bool
    simulate (IN a) c = findIn c a
    simulate (NOT a) c = not $ simulate a c
    simulate (AND a b) c = all (simulate a c) (simulate b c)
    simulate (OR a b) c = any (simulate a c) (simulate b c)
    simulate (XOR a b) c = xor (simulate a c) (simulate b c)

    Another problem is that all :: Foldable t => (a -> Bool) -> t a -> Bool function [Hackage], and any :: Foldable t => (a -> Bool) -> t a -> Bool function [Hackage] work with a Foldable of items, not two parameters; so:

    simulate :: Circ -> [(String, Bool)] -> Bool
    simulate (IN a) c = findIn c a
    simulate (NOT a) c = not $ simulate a c
    simulate (AND a b) c = simulate a c && simulate b c
    simulate (OR a b) c = simulate a c || simulate b c
    simulate (XOR a b) c = simulate a c `xor` simulate b c

    But we can probably simplify this by making abstraction of the operator:

    data Op1 = Not
    
    data Op2 = And | Or | Xor
    
    data Circ
      = IN String
      | Op1 Op1 Circ
      | Op2 Op2 Circ Circ

    and work with:

    func1 :: Op1 -> Bool -> Bool
    func1 Not = not
    
    func2 :: Op2 -> Bool -> Bool -> Bool
    func2 And = (&&)
    func2 Or = (||)
    func2 Xor = xor
    
    simulate :: Circ -> [(String, Bool)] -> Bool
    simulate (IN a) c = findIn c a
    simulate (Op1 f a) c = func1 f (simulate a c)
    simulate (Op2 f a b) c = func2 f (simulate a c) (simulate b c)