Haskell - 求和概率列表

时间:2016-06-05 10:52:04

标签: haskell fold

我正在经历“了解你是一个哈斯克尔”,刚刚完成了“为了更多的单子”这一部分。在这部分中,我们创建了一个newtype Prob a = Prob { getProb :: [(a, Rational)] }并为其创建了一个Monad实例。这允许我们在非确定性计算中计算结果的概率,如下所示:

data Coin = Heads | Tails deriving (Show, Eq)

coin :: Prob Coin
coin = Prob [(Heads, 1%2), (Tails, 1%2)]

loadedCoin :: Prob Coin
loadedCoin = Prob [(Heads, 1%10), (Tails, 9%10)]

coinTest :: Prob Bool
coinTest = do
    a <- coin
    b <- coin
    c <- loadedCoin
    return (all (==Tails) [a,b,c])

当然,这不会产生非常漂亮的结果:

getProb coinTest
>> [(False,1 % 40),(False,9 % 40),(False,1 % 40),(False,9 % 40),(False,1 % 40),(False,9 % 40),(False,1 % 40),(True,9 % 40)]

作为练习,读者可以编写一个简洁的函数来总结所有False和所有True,以便得到[(True,9 % 40),(False,31 % 40)]。我设法做到了这一点。它适用于这种特殊情况,但我觉得它根本不是一个有用的功能,因为它是如此专业。这就是我想出的:

sumProbs :: Prob Bool -> Prob Bool
sumProbs (Prob ps) = let (trues, falses) = partition fst ps
                         ptrue = reduce trues
                         pfalse = reduce falses
                     in Prob [ptrue, pfalse]
                     where reduce = foldr1 (\(b,r) (_,r') -> (b,r+r'))

我喜欢将它推广到任何Eq a => Prob a,但到目前为止还没有运气。我在考虑使用MapunionWith或类似的东西。或者我可以利用(a,b)有一个Functor b实例的事实?我想我错过了一些更简单更优雅的解决方案。

所以,总结一下:我如何编写一个函数sumProbs :: (Eq a) => Prob a -> Prob a来总结所有共享相同值(密钥)的概率?

2 个答案:

答案 0 :(得分:2)

使用Map是一个好主意,但除了Ord a之外,您还需要Eq a。如果你对此感到满意,那么我们也可以做更简单的列表解决方案:只需用sortBygroupBy的组合替换partition

import Data.List (groupBy, sortBy)
import Data.Function (on)

sumProbs :: (Ord a) => Prob a -> Prob a
sumProbs (Prob ps) = Prob . map reduce
                   . groupBy ((==)`on`fst)
                   $ sortBy (compare`on`fst) ps

答案 1 :(得分:2)

如果您使用CGRect frame = self.view.frame; frame.size.height = self.superViewHeight; self.view.frame = frame; ,那么fromListWithtoList就可以:

Data.Map

放宽import Data.Map (toList, fromListWith) newtype Prob a = Prob { getProb :: [(a, Rational)] } deriving Show sumProbs :: (Ord a) => Prob a -> Prob a sumProbs = Prob . toList . fromListWith (+) . getProb Ord a需要效率较低的二次计算;类似的东西:

Eq a