这是我正在尝试做的事情:
isPrime :: Int -> Bool
isPrime x = all (\y -> x `mod` y /= 0) [3, 5..floor(sqrt x)]
(我知道我不会检查两个分区 - 请忽略它。) 这是我得到的:
No instance for (Floating Int)
arising from a use of `sqrt'
Possible fix: add an instance declaration for (Floating Int)
In the first argument of `floor', namely `(sqrt x)'
In the expression: floor (sqrt x)
In the second argument of `all', namely `[3, 5 .. floor (sqrt x)]'
我花了好几个小时尝试了我能想到的一切,使用sqrt的一些变体来制作这个列表,包括像
这样的废话intSqrt :: Int -> Int
intSqrt x = floor (sqrt (x + 0.0))
似乎(sqrt 500)工作正常但是(sqrt x)坚持x是浮动(为什么?),并且没有找到将Int转换为实数的函数(为什么?)。
我不想要一种测试素性的方法,我想了解如何解决这个问题。为什么这么难?
答案 0 :(得分:21)
与大多数其他语言不同,Haskell严格区分整数和浮点类型,并且不会隐式地将一个转换为另一个。有关如何明确执行转换,请参阅here。甚至有sqrt
例子: - )
潜在的原因是隐式转换和Haskel(相当复杂但非常酷)的类系统的组合会使类型重建变得非常困难 - 可能它会超出它可以由机器完成的程度。所有。语言设计者认为获取算术类型类是值得明确指定转换的成本。
答案 1 :(得分:19)
您的问题是,虽然您尝试以各种方式修复它,但您还没有尝试过x
,这正是您的问题所在。我们来看看sqrt
:
Prelude> :t sqrt
sqrt :: (Floating a) => a -> a
另一方面,x
是Int
,如果我们向GHCi询问有关Floating
的信息,它会告诉我们:
Prelude> :info Floating
class (Fractional a) => Floating a where
pi :: a
<...snip...>
acosh :: a -> a
-- Defined in GHC.Float
instance Floating Float -- Defined in GHC.Float
instance Floating Double -- Defined in GHC.Float
因此,Floating
的唯一类型是Float
和Double
。我们需要一种方法将Int
转换为Double
,就像floor :: (RealFrac a, Integral b) => a -> b
转向另一个方向一样。每当你遇到这样的类型问题时,你可以问Hoogle,这是一个搜索类型的Haskell搜索引擎。不幸的是,如果你搜索Int -> Double
,你会得到糟糕的结果。但是,如果我们放松我们正在寻找的东西呢?如果我们搜索Integer -> Double
,我们会发现有一个函数fromInteger :: Num a => Integer -> a
,这几乎就是您想要的。如果我们将我们的类型一直放到(Integral a, Num b) => a -> b
,您会发现有一个函数fromIntegral :: (Integral a, Num b) => a -> b
。
因此,要计算整数的平方根,请使用floor . sqrt $ fromIntegral x
或使用
isqrt :: Integral i => i -> i
isqrt = floor . sqrt . fromIntegral
您正在考虑sqrt
输出正确方向的问题;它返回一个浮点数,但你想要一个整数。但是,在Haskell中,没有子类型或隐式强制转换的概念,因此您还需要将输入更改为sqrt
。
解决您的其他一些问题:
intSqrt :: Int -> Int intSqrt x = floor (sqrt (x + 0.0))
你称之为“废话”,所以很明显你不指望它能起作用,但为什么不呢?好吧,问题是(+)
的类型为Num a => a -> a -> a
- 你只能添加两个相同类型的东西。这通常是好的,因为这意味着你不能将复数加到5×5实矩阵中;但是,由于0.0
必须是Fractional
的实例,因此您无法将其添加到x :: Int
。
似乎(sqrt 500)工作正常......
这是有效的,因为500
的类型不是您所期望的。让我们问一下我们可信赖的同伴GHCi:
Prelude> :t 500
500 :: (Num t) => t
实际上,所有整数文字都有这种类型;它们可以是任何类型的数字,这是有效的,因为Num
类包含函数fromInteger :: Integer -> a
。因此,当您撰写sqrt 500
时,GHC意识到500
需要满足500 :: (Num t, Floating t) => t
(并且它会隐含地选择Double
这样的数字类型,感谢defaulting rules )。同样,由于0.0
的{{1}}函数,上面的Fractional t => t
类型为Fractional
。
...但是(sqrt x)坚持认为x是浮动...
见上文,我们查看fromRational :: Rational -> a
的类型。
...并且我找不到将Int转换为真实的函数....
嗯,你现在有一个:sqrt
。我不知道为什么你找不到它;显然Hoogle的结果比我预期的要糟糕得多,这要归功于函数的泛型类型。
为什么这么难?
我希望现在已经没有了fromIntegral
。