如何在`.hs`文件中定义复合函数的'特殊'行为?

时间:2013-04-18 18:03:07

标签: haskell

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,但是)。

2 个答案:

答案 0 :(得分:13)

首先,您在GHCi中的示例并未定义floorsqrt的特殊组合。相反,它定义了一个运算符(.),它接受​​名为floorsqrtn的三个参数,并隐藏现有的名为(.)的标准函数。

然后,您将新功能应用于标准库函数floorsqrt,这些函数将成为新(.)函数中具有相同名称的参数。

您得到的错误是因为顶级定义不会自动隐藏现有定义,无论如何,这显然不是您真正想要做的。

现在,您当然可以定义一个全新的函数(希望使用自己的名称,如在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)