Eric Flaten
Eric Flaten

Reputation: 61

How do I use map to generalize a function

I am trying to design a Haskell program to build a game theory tree that creates a Game (capital G) by repeatedly playing a base game (small G) a specified number of times.

The foo function below works correctly by adding the outcome (or payoff) of one round to each of the outcomes/payoffs of the base game. One major limitation is that the base game is permanently set to have three outcomes.

The foo' function (which does not work) is supposed to be a generalization of the foo function. That is to mimic the foo function by using the map function and a list of values that represent the base game.

data MyTree a = Root a [MyTree a] | Branch a [MyTree a] | Leaf a | EmptyNode deriving Show

x1:: Integer
x1 = 1

x2 :: Integer
x2 = 25

x3 :: Integer
x3 = 100

foo :: [Integer] -> MyTree [Integer] 
foo [r, a] 
    | r == 0      = Leaf   [a] 
    | a == 0      = Root   [a] [foo [r-1, a+x1], foo [r-1, a+x2], foo [r-1, a+x3]]
    | otherwise   = Branch [a] [foo [r-1, a+x1], foo [r-1, a+x2], foo [r-1, a+x3]]

lst = [x1, x2, x3]

foo' :: [Integer] -> MyTree [Integer] 
foo' [r, a] 
    | r == 0      = Leaf   [a] 
    | a == 0      = Root   [a] map (foo'.(\y ->[r-1, y]).(\x -> a+x)) lst
    | otherwise   = Branch [a] map (foo'.(\y ->[r-1, y]).(\x -> a+x)) lst

The following errors show up twice (one for the a == 0 line and for the otherwise line). I list them only once since once I know how to fix an error, I can fix its duplicate.

The error messages I get are (a) and (b):

Couldn't match expected type ‘([Integer] -> MyTree [Integer]) -> [[Integer]] -> MyTree [Integer]’with actual type ‘MyTree [Integer]’


Couldn't match expected type ‘[MyTree [Integer]]’with actual type ‘(a0 -> b0) -> [a0] -> [b0]’

My question is this: How can I get the actual input to match the expected input? I've spent many days and hours working on the syntax and Google-searching for the solution.

Upvotes: 1

Views: 95

Answers (1)

Igor Drozdov
Igor Drozdov

Reputation: 15045

The problem is just what the compiler says:

The function ‘Root’ is applied to four arguments, but its type ‘[Integer] -> [MyTree [Integer]] -> MyTree [Integer]’ has only two

That's because compiler assumes that [a], map, (foo'.(\y ->[r-1, y]).(\x -> a+x)) and lst are four separate arguments to function Root.

It can be fixed either by using $, which sets the priority of evaluation

foo' :: [Integer] -> MyTree [Integer] 
foo' [r, a] 
    | r == 0      = Leaf   [a] 
    | a == 0      = Root   [a] $ map (foo'.(\y ->[r-1, y]).(\x -> a+x)) lst
    | otherwise   = Branch [a] $ map (foo'.(\y ->[r-1, y]).(\x -> a+x)) lst

Or, since it can be moved into a separate function (probably genList name is not appropriate, certainly you can make up a better one):

foo' :: [Integer] -> MyTree [Integer]
foo' [r, a]
    | r == 0      = Leaf   [a]
    | a == 0      = Root   [a] genList
    | otherwise   = Branch [a] genList
    where genList = map (foo'.(\y ->[r-1, y]).(\x -> a+x)) lst

Upvotes: 2

Related Questions