我是Haskell的新手(以及一般的函数式编程),我正在尝试编写一个名为的函数 " profileDistance m1 m2"这需要两个矩阵作为参数,需要计算每个矩阵中每个元素之间差异的总和...我可能没有很好地解释。让我反过来说明一下。
矩阵的形式为:[[(Char,Int)]]
每个矩阵可能看起来像这样:
m1 = [[('A',1),('A',2)],
[('B',3),('B',4)],
[('C',5),('C',6)]]
m2 = [[('A',7),('A',8)],
[('B',9),('B',10)],
[('C',11),('C',12)]]
(注意:我在这个例子中按顺序编写了数字,但它们可以是任何顺序的任何数字。但是每个矩阵中每行的字符将匹配,如示例中所示。)
结果(在上面的例子中)看起来像(伪代码):
result = ((snd m1['A'][0])-(snd m2['A'][0]))+((snd m1['A'][1])-(snd m2['A'][1]))+((snd m1['B'][0])-(snd m2['B'][0]))+((snd m1['B'][1])-(snd m2['B'][1]))+((snd m1['C'][0])-(snd m2['C'][0]))+((snd m1['C'][1])-(snd m2['C'][1]))
在任何具有for循环且无功能的语言中这很容易做到,但我不知道如何在Haskell中执行此操作。我觉得像map
,fold
或sum
这样的功能会对我有所帮助(诚然,我对fold
的工作方式并不是100%肯定)。我希望有一个简单的方法可以做到这一点......请帮助。
答案 0 :(得分:6)
这是一个提案:
solution m1 m2 = sum $ zipWith diffSnd flatM1 flatM2
where
diffSnd t1 t2 = snd t1 - snd t2
flatM1 = concat m1
flatM2 = concat m2
我写了它,以便更容易理解构建块。
基本思想是使用zipWith
同时迭代我们的两个对列表。这是它的类型:
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
这意味着它需要一个类型为a -> b -> c
的函数,一个a
列表和一个b
列表,并返回一个列表c
的{{1}}。换句话说,zipWith
接受迭代的情况,你只需要指定你想对迭代产生的每个项目做什么,在你的情况下将是一对(一个来自第一个矩阵,另一个)一个来自第二个)。
传递给zipWith
的函数从每对中获取snd
元素,并计算差异。回顾zipWith
签名,您可以推断它将返回一个数字列表。所以我们需要做的最后一件事是使用函数sum
对它们进行求和。
还有最后一个问题。实际上我们没有两个对的列表要传递给zipWith
!,而是两个矩阵。我们需要“平坦化”#34;它们在列表中,保留元素的顺序。这正是concat
的作用,因此在flatM1
和flatM2
的定义中对该函数的调用。
我建议你研究一下我提到的每个函数的实现,以便更好地掌握迭代是如何通过递归来表示的。 HTH