Combining elements with probabilities in Haskell

时间:2017-04-10 00:39:29

标签: haskell functional-programming

I'm working through the For A Few Monads More chapter in Learn You A Haskell For Great Good, and in the last section, they define a type representing outcomes with probabilities as follows:

newtype Prob a = Prob { getProb :: [(a,Rational)] } deriving Show  

There's an exercise at the end of the section on combining probabilities that represent the same outcome, and I'm trying to figure out the best way to approach this.

We see that our monad doesn't know how to join all of the False outcomes where all coins don't land tails into one outcome. That's not a big problem, since writing a function to put all the same outcomes into one outcome is pretty easy and is left as an exercise to the reader (you!)

I'm still not quite used to the functional way of thinking, but I feel like this could be accomplished using a fold over all the outcomes in the list to check if the outcome exists in the accumulator. If it doesn't exist, we simply add the outcome to the accumulator and if it does exist, we just need to update the outcome in the accumulator by adding the probabilities.

Am I on the right track, or am I thinking about this the wrong way?

EDIT: This is my attempt at implementing this:

outcomeExists ::  [(Bool, Rational)] -> Bool -> Bool
outcomeExists xs out  = (length $ filter (\(a,b) -> a == out) xs) > 0

probFold :: [(Bool,Rational)] -> (Bool, Rational) -> [(Bool,Rational)]
probFold acc (out,prob)
    | outcomeExists acc out = [if a == out then (a,b+prob) else (a,b) | (a,b) <- acc]
    | otherwise             = (out,prob):acc

Is a list comprehension the best way to modify the matching outcome in the accumulator? I couldn't think of anything else that would be cleaner.

Also, while this seems to work in ghci when I enter Prob (foldl probFold [] (getProb flipThree )), where flipThree has type Prob Bool, I'm having trouble defining a function that takes a Prob Bool and produces the same output.

When I try to compile this:

combineOutcomes :: Prob Bool -> Prob Bool
combineOutcomes (Prob a) = Prob[foldl probFold [] a]

I get this error, but I don't understand why there's a type mismatch, since it works fine in ghci.

monads.hs:89:33: error:
    • Couldn't match expected type ‘(Bool, Rational)’
                  with actual type ‘[(Bool, Rational)]’
    • In the expression: foldl probFold [] a
      In the first argument of ‘Prob’, namely ‘[foldl probFold [] a]’
      In the expression: Prob [foldl probFold [] a]

1 个答案:

答案 0 :(得分:0)

You are on the right track. Give it a shot, then if you get stuck ask us again with further details on what's giving you trouble!