我正在经历“了解你是一个哈斯克尔”,刚刚完成了“为了更多的单子”这一部分。在这部分中,我们创建了一个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
,但到目前为止还没有运气。我在考虑使用Map
和unionWith
或类似的东西。或者我可以利用(a,b)
有一个Functor b
实例的事实?我想我错过了一些更简单更优雅的解决方案。
所以,总结一下:我如何编写一个函数sumProbs :: (Eq a) => Prob a -> Prob a
来总结所有共享相同值(密钥)的概率?
答案 0 :(得分:2)
使用Map
是一个好主意,但除了Ord a
之外,您还需要Eq a
。如果你对此感到满意,那么我们也可以做更简单的列表解决方案:只需用sortBy
和groupBy
的组合替换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;
,那么fromListWith
和toList
就可以:
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