Haskell中的组合非常正常,但我只知道我可以定义复合函数的特殊行为,
Prelude> (floor . sqrt) (10^55)
3162277660168379365112938496
Prelude> let (floor . sqrt) n | n < 2 = n | otherwise = head $ dropWhile (\x -> x^2 > n) $ iterate (\x -> (x + n `div` x) `div` 2) (n `div` 2)
Prelude> (floor . sqrt) (10^55)
3162277660168379331998893544
特殊定义函数的结果是正确的(因为第一个中的浮点错误)。
现在我想在.hs
文件中执行相同操作,例如
(floor . sqrt) n
| n < 2 = n
| otherwise = head $ dropWhile (\x -> x^2 > n)
$ iterate (\x -> (x + n `div` x) `div` 2) (n `div` 2)
main = do
print $ (floor . sqrt) (10^55)
这次ghc
对我大喊大叫
Ambiguous occurrence `.'
It could refer to either `Main..', defined at me.hs:1:8
or `Prelude..',
imported from `Prelude' at me.hs:1:1
(and originally defined in `GHC.Base')
那么可以在.hs
文件中定义这样的函数吗? (在main
里面定义它let
是okey,但是)。
答案 0 :(得分:13)
首先,您在GHCi中的示例并未定义floor
和sqrt
的特殊组合。相反,它定义了一个运算符(.)
,它接受名为floor
,sqrt
和n
的三个参数,并隐藏现有的名为(.)
的标准函数。
然后,您将新功能应用于标准库函数floor
和sqrt
,这些函数将成为新(.)
函数中具有相同名称的参数。
您得到的错误是因为顶级定义不会自动隐藏现有定义,无论如何,这显然不是您真正想要做的。
现在,您当然可以定义一个全新的函数(希望使用自己的名称,如在groovy的答案中)来执行您的专用floor . sqrt
函数,但Haskell本身无法将其定义为专用版本现有的职能。
您可能正在考虑并且可能在GHC中使用compiler pragma rewrite rules来自动使用等效的改进版本替换特定表达式。但是,您应该小心,您的重写形式会给出与其替换相同的答案。否则你会冒一些令人困惑的调试会话。
答案 1 :(得分:1)
这个怎么样?
floorSqrt n
| n < 2 = n
| otherwise = head $ dropWhile (\x -> x^2 > n)
$ iterate (\x -> (x + n `div` x) `div` 2) (n `div` 2)
main = do
print $ floorSqrt (10^55)