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

3

组合在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
< p > 由于浮点数误差,< em >special定义函数的结果是正确的(与第一个函数相比)。 < p>现在我想在< code > .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 定义是可以的)。

9
你做不到。(floor . sqrt) nfloorsqrt视为变量而不是函数,所以这对于所有名为floorsqrt的函数都适用。最好说(g. f) n。至于你的特殊化自定义,这在Haskell中是不可能的,你必须以其他方式获取所需内容。 - luqui
2个回答

13
首先,在 GHCi 中你的例子没有定义一个特殊的 floorsqrt 的合成。相反,它定义了一个名为 (.) 的运算符,它带有三个参数,分别被命名为 floorsqrtn,并隐藏了现有的标准函数 (.)
然后,你将你的新函数应用于标准库函数 floorsqrt,它们成为你的新函数中具有相同名称的参数。
你得到的错误是因为顶级定义不会自动隐藏现有的定义,而且这显然也不是你想要做的事情。
现在,你可以确实定义一个全新的函数(希望它有自己的名称,就像 groovy 的答案一样),来做你专门的 floor . sqrt 函数,但在 Haskell 中不存在这样定义它作为现有函数的专门版本的方法。
你可能在想,也有可能实现,的是使用 GHC 中的 编译器指示重写规则 自动替换特定表达式为等效、改进的版本。但你需要小心,确保重写后的形式与原先的答案相同,否则会冒着一些难以理解的调试问题的风险。

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)

我只是想尝试一些概念,这是我现在通常的做法。 - neizod

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接