gpt4 book ai didi

Haskell 类型错误

转载 作者:行者123 更新时间:2023-12-02 14:08:56 25 4
gpt4 key购买 nike

第一天学习 haskell,并且来自 python 背景,我在打字方面确实遇到了调试问题;目前我正在开发一个简单的函数来查看一个数字是否是素数;

prime p = if p == 1 then False else if p == 2 then True else if maximum ([if p `mod` x == 0 then x else -1 | x<-[2..(floor(p**0.5))]]) > 0 then False else True

当我有一个特定的数字而不是通用的 P 时,它就可以工作,但无论我尝试什么(并且我已经尝试了很多,包括只是转向不同的问题),我总是会遇到某种有关类型的错误。对于当前的迭代,我收到错误

<interactive>:149:1: error:
* Ambiguous type variable `a0' arising from a use of `prime'
prevents the constraint `(RealFrac a0)' from being solved.
Probable fix: use a type annotation to specify what `a0' should be.
These potential instances exist:
instance RealFrac Double -- Defined in `GHC.Float'
instance RealFrac Float -- Defined in `GHC.Float'
...plus one instance involving out-of-scope types
(use -fprint-potential-instances to see them all)
* In the expression: prime 2
In an equation for `it': it = prime 2

<interactive>:149:7: error:
* Ambiguous type variable `a0' arising from the literal `2'
prevents the constraint `(Num a0)' from being solved.
Probable fix: use a type annotation to specify what `a0' should be.
These potential instances exist:
instance Num Integer -- Defined in `GHC.Num'
instance Num Double -- Defined in `GHC.Float'
instance Num Float -- Defined in `GHC.Float'
...plus two others
...plus one instance involving out-of-scope types
(use -fprint-potential-instances to see them all)
* In the first argument of `prime', namely `2'
In the expression: prime 2
In an equation for `it': it = prime 2

如果有人能够在调试这个特定程序的同时,让我了解如何思考 haskell 类型,我将非常感激。我尝试过查看 learnyouahaskell,但到目前为止我还没有成功应用它。

最佳答案

简而言之:同时使用 modfloor(**) ,您对 p 的类型限制很多,Haskell 无法找到调用 prime 的数值类型。

这里的主要问题在于列表理解的可迭代:

[2..(floor(p**0.5))]

这里您调用 p ** 0.5,但由于 (**) 的类型为 (**) :: Floating a => a -> a -> a ,这意味着 p 必须是 Floating 类型类实例的类型实例,例如 Float。我猜你不希望这样。

您的floor :: (RealFrac a, Integral b) => a -> b甚至使情况变得更糟,因为现在 p 也必须是 RealFrac 类型类实例的类型。

另一方面,您使用 mod :: Integral a => a -> a -> a ,因此这意味着您的 p 必须是 Floating 以及 Integral,它们是两个析取集:尽管严格来说,我们可以定义这样的类型,但是一个数字在同一类型上同时是IntegralFloating是相当奇怪的。例如,Float 是一个 Floating 数字,但不是 Integral,而 IntIntegral >,但不是 Floating 类型。

我们必须找到一种方法来放松对p的限制。由于通常非整数数字根本不是素数,因此我们最好的目标是丢弃floor(**)。然而,迭代到 p 的平方根的优化是一个好主意,但我们需要找到其他方法来强制执行。

实现此目的的一种方法是使用 takeWhile :: (a -> Bool) -> [a] -> [a]我们取元素,直到数字的平方大于 p,因此我们可以将 [2..(floor(p**0.5))] 重写为:

takeWhile (\x -> x * x <= p) [2..]

我们甚至可以只使用奇数元素和 2,将其写为:

takeWhile (\x -> x * x <= p) (2:[3, 5..])

如果我们使用设置为 99p 进行测试,我们会得到:

Prelude> takeWhile (\x -> x * x <= 99) (2:[3, 5..])
[2,3,5,7,9]

如果我们将其插入,我们就放宽了类型:

prime p = if p == 1 then False else if p == 2 then True else if maximum ([if p `mod` x == 0 then x else -1 | x <- takeWhile (\x -> x * x <= p) (2:[3, 5..])]) > 0 then False else True

我们实际上已经足够放松了:

Prelude> :t prime
prime :: Integral a => a -> Bool

我们得到:

Prelude> prime 23
True

但是代码非常丑陋并且非Haskell。首先,您在这里使用 maximum 作为技巧来检查所有元素是否满足谓词。但这样做是没有意义的:从一个元素可整除的那一刻起,我们就知道这个数字不是素数。这样我们就可以更好的利用all :: (a -> Bool) -> [a] -> Bool功能。此外,通常使用模式匹配和防护来检查条件,因此我们可以这样写:

prime :: Integral a => a -> Bool
prime n | n < 2 = False
| otherwise = all ((/=) 0 . mod n) divisors
where divisors = takeWhile (\x -> x * x <= n) (2:[3, 5..])

关于Haskell 类型错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50254694/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com