您的问题是,尽管您尝试以各种方式修复它,但您没有尝试做某事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
s 和Double
s。我们需要一种将 a 转换Int
为 a的方法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) 工作正常……</p>
这是有效的,因为类型500
不是您所期望的。让我们问问我们值得信赖的伙伴 GHCi:
Prelude> :t 500
500 :: (Num t) => t
事实上,所有整数文字都有这种类型;它们可以是任何类型的数字,因为Num
该类包含 function fromInteger :: Integer -> a
。因此,当您编写时sqrt 500
,GHC 意识到500
需要满足(并且由于默认规则500 :: (Num t, Floating t) => t
,它会隐式选择Double
类似的数字类型)。同样,上面有 type ,这要归功于's功能。0.0
Fractional t => t
Fractional
fromRational :: Rational -> a
…但是 (sqrt x) 坚持 x 是一个 Floating …</p>
见上文,我们在其中查看sqrt
.
……我找不到将 Int 转换为真实的函数……。
好吧,你现在有一个:fromIntegral
。我不知道你为什么找不到它;显然,由于函数的泛型类型,Hoogle 给出的结果比我预期的要差得多。
为什么这么难?
我希望它不再是了,现在你有了fromIntegral
。