将函数应用于具有替换

时间:2017-09-06 11:36:22

标签: haskell functional-programming

我试图创建一个快速计算分数的函数。在我的特殊情况下有一个阶乘,所以它有点容易。我写了一个make_coprime函数,它使两个数字互质(并返回一对,这让我感到困扰:它听起来有点太复杂,有没有办法让它返回2个数字?看起来没有&#39 ; t,但只是为了确定)

现在它就像压裂{数字] / {数字}一样,我想让所有较高的那些与所有较低层相互作用。

所以我有两个列表,我希望在之后将我的函数应用于所有可能的替换对。这是我失败的地方。我甚至不能用一个元素和一个列表来做,我最好的是

f a [] = (a, [1])
f a x:xs = ((fst (make_coprime a x)), ((snd (make_coprime a x)):(snd (f (fst (make_coprime a x)) xs))))

(这里有一个解析错误,但我根本找不到它)

但我觉得我过于复杂。它听起来比我写它时看起来更简单。是否有一种优雅的方式来做到这一点?

2 个答案:

答案 0 :(得分:4)

您只需拨打coprime a x一次;您可以使用let语句将其返回值分配给名称:

f a (x:xs) = let pair = make_coprime a x 
             in  ((fst pair), ((snd pair):(snd (f (fst pair) xs))))

(您的解析错误可能是由于x:xs周围缺少括号。)

您可以立即解压缩对,而不是反复调用fstsnd来简化它。

f a (x:xs) = let (n1,n2) = make_coprime a x 
             in  (n1, (n2:(snd (f n1 xs))))

答案 1 :(得分:4)

解析错误是您没有在x:xs周围使用parens。

在再说之前:Haskell函数应该总是带有类型签名,这使得我们更容易推理出我们正在讨论的内容以及任何内容。我不确定你想要什么,但很可能

makeCoprime :: Integer -> Integer -> (Integer,Integer)

f :: Integer -> [Integer] -> (Integer, [Integer])

除此之外(并且为了找到在类型系统采取行动之前发生的其他解析错误),我首先尝试将其写为尽可能可读。首先有意义地对齐一切:

f a (x:xs) = ( (fst (make_coprime a x))
             , ( (snd (make_coprime a x))
                 : (snd (f (fst (make_coprime a x)) xs))
               )
             )
好的,现在有几个必要的parens,应该省略:,总是分开所有内容,所以你永远不需要写,例如(1, (2)):只需将其(1,2)。并且函数应用程序比任何中缀运算符更紧密地绑定 ,因此您也永远不需要编写(f x) : y,只需执行f x : y。这使你的代码

f a (x:xs) = ( fst (make_coprime a x)
             , snd (make_coprime a x)
                 : snd (f (fst (make_coprime a x)) xs)
             )

这已经很容易理解。你可以使用$.运算符摆脱更多的parens,但我会离开。

正如切普纳所说,我绝对不会留下make_coprime a x的这些多重调用。这种重复不仅是代码噪声,它还可以使你的程序运行得很慢。

f a (x:xs) = ( fst axCoprimes
             , snd axCoprimes
                 : snd (f (fst axCoprimes) xs)
             )
 where axCoprimes = make_coprime a x

现在,您使用axCoprimes所做的只是分别评估fstsnd组件。因此,不应给出元组一个名称,而应立即匹配组件:

f a (x:xs) = (p₀, p₁ : snd (f p₀ xs))
 where (p₀,p₁) = make_coprime a x

然后你去了,IMO看起来非常清楚。