首页 > 解决方案 > 在 Haskell 中减少由 Bool 和 Rational 值组成的条目的列表

问题描述

我得到一个列表,其中包含由 Bool 和 Rational 值组成的条目,如下所示:

[(False,1 % 40),(False,9 % 40),(False,1 % 40),(False,9 % 40),  
 (False,1 % 40),(False,9 % 40),(False,1 % 40),(True,9 % 40)]

我想将共享 Bool 值的条目减少为一个,并将相应的 Rational 值相加。

上述示例的结果应如下所示:

[(False,31 % 40),(True,9 % 40)]

我是 Haskell 的新手,并尝试使用 foldM 完成任务,但我认为这不是正确的方法。

任何帮助深表感谢。

标签: listhaskell

解决方案


您确实可以在fold这里使用 a 。我将在这里使用一个 2 元组,例如,第一个元素包含Falses 的总和,第二个元素包含 s 的总和True

import Control.Arrow(first, second)
import Data.Bool(bool)

dsum :: (Foldable f, Num a) => f (Bool, a) -> (a, a)
dsum = foldr (uncurry ((. (+)) . bool first second)) (0,0)

对于可折叠的(Bool, a)元组,它将计算一个 2 元组,其中第一个元素包含(False, ...)元组的总和,第二个元素包含元组的总和(True, ...)

(uncurry ((. (+)) . bool first second))是一个函数的紧凑表示f

f :: Num a => (Bool, a) -> (a, a) -> (a, a)
f (False, d) (a, b) = (d+a, b)
f (True, d) (a, b) = (a, d+b)

例如:

Prelude> d = [(False,1 % 40),(False,9 % 40),(False,1 % 40),(False,9 % 40), (False,1 % 40),(False,9 % 40),(False,1 % 40),(True,9 % 40)]
Prelude> dsum d
(31 % 40,9 % 40)

通过使用 2 元组,我们因此添加了一个“合同”,我们将恰好有两个元素,这通常比总是包含两个项目的列表更可取。


推荐阅读