检查列表中的值以查看具有单个变量的Coprime

时间:2014-09-16 05:10:33

标签: haskell recursion

我在Haskell中实现此功能时遇到一些麻烦。以下是我到目前为止的情况:

--Extend coprime to a function on lists:
--coprime_with n list = True exactly when n is coprime with
--every element of list.

coprime_with :: Integer -> [Integer] -> Bool
coprime_with a [] = False
coprime_with a (b:bs) = if ((coprime a b) == True) then 
                          (coprime_with a bs)
                        else False

希望这不会让人感到困惑。请不要给我答案。只是让我知道我做错了什么以及如何解决它。谢谢!

编辑:好的,我明白了!非常感谢您的回复。它非常快。我是Comp Sci专业,这是我的第一个学期。我的目标是实际学习,而不仅仅是通过它。感谢您的回复以及您的措辞。

我的问题是:

coprime_with a [] = False

应该是这样的:

coprime_with a [] = True

现在它正常运作。 Phew ...我觉得很愚蠢,我花了五个小时写这个功能,但至少我实际上学到了一些东西。再次感谢!

2 个答案:

答案 0 :(得分:5)

很高兴您找到了问题所在。您可以从中获得更多的课程。

所以你现在有了

coprime_with :: Integer -> [Integer] -> Bool
coprime_with a []     = True
coprime_with a (b:bs) = if ((coprime a b) == True) then 
                          (coprime_with a bs)
                        else False

每当您看到 A 然后 B 其他错误 时,您可以将其替换为 < em> A &amp;&amp;的 的。你知道为什么吗?

每当您看到 A == True 时,您只需将其替换为 A 即可。你知道为什么吗?

现在我们有了

coprime_with a (b:bs) = (coprime a b) && (coprime_with a bs)

参数a永远不会改变,但我们不必要地将它传递给每个递归调用。另一方面,我们必须拥有它,因为它是coprime_with的全部内容。解决方案是引入内部函数,

coprime_with a bs = g bs      -- "g" is "coprime_with a"
   where
     g []     = True
     g (b:bs) = coprime a b && g bs

(我们可以在没有括号的情况下编写它,因为Haskell中的功能应用程序具有最高优先级)。

这被称为worker/wrapper transform。它使我们的代码更清晰,并允许编译器执行更多优化。我们的新g是工作者,coprime_with是包装g的包装器。 g有一个不同的类型,coprime_with负责为它提供正确的参数(这里只是第二个),并将其结果转换回预期的(这里只是传递它们)。

接下来,我们可以在Haskell中为我们想要的任何(子)表达式赋予一个新名称。在这里,我们会做

coprime_with a bs = g pred bs    -- "pred" is for "predicate"
   where
     g pred []     = True
     g pred (b:bs) = pred b && g pred bs
     pred = coprime a

这有什么意义?你问,我们回过头来递送额外的递归参数吗?正确!这不是优化,而只是重写,旨在某处。接下来,我们甚至可以替换pred

的定义
coprime_with a bs = g (coprime a) bs
   where
     g :: (a -> Bool) -> [a] -> Bool
     g pred []     = True
     g pred (b:bs) = pred b && g pred bs

那是我们的目的地。剩下的就是要意识到我们已经重新设计了一个轮子(其中一个轮子)。您可以在searching for g's type on Hoogle找到它的内容,并检查那里的少数热门匹配的来源,看看哪一个是我们的g。提示:您已在评论中建议使用它。


现在我们可以清楚地看到为什么必须在空列表中返回True而不是False。我们的g检查谓词是否适用于列表的所有元素。换句话说,如果列表中的某个元素未通过谓词,它必须失败(意味着此处,返回False) - 否则返回True!但是空列表中没有元素可以使谓词失败。

(我喜欢此问题的另一种解释是basically says,因为g (a++b) == g a && g ba == a ++ [],它必须包含g a == g (a++[]) == g a && g [])。

答案 1 :(得分:1)

您正在寻找的答案是改变

coprime_with a [] = False

coprime_with a [] = True

当列表进入最后的递归阶段时,它已变成一个空列表。它进入空白阶段的事实意味着列表中的所有数字都是互质的。但是,参数的设置方式是,当列表为空时,它被设置为读取&#34; False&#34;。只需将该条件更改为&#34; True&#34;解决了这个问题。