我试图创建一个快速计算分数的函数。在我的特殊情况下有一个阶乘,所以它有点容易。我写了一个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))))
(这里有一个解析错误,但我根本找不到它)
但我觉得我过于复杂。它听起来比我写它时看起来更简单。是否有一种优雅的方式来做到这一点?
答案 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
周围缺少括号。)
您可以立即解压缩对,而不是反复调用fst
和snd
来简化它。
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
所做的只是分别评估fst
和snd
组件。因此,不应给出元组一个名称,而应立即匹配组件:
f a (x:xs) = (p₀, p₁ : snd (f p₀ xs))
where (p₀,p₁) = make_coprime a x
然后你去了,IMO看起来非常清楚。