使用 uncurry 函数进行特定类型推断

发布于 2024-10-17 04:39:35 字数 533 浏览 4 评论 0原文

我一直在使用 GHCi 中的 uncurry 函数,但发现了一些我根本无法理解的东西。当我将 uncurry 应用于 (+) 函数并将其绑定到某个变量(如下面的代码所示)时,编译器会推断其类型特定于 Integer< /code>:

Prelude> let add = uncurry (+)
Prelude> :t add
add :: (Integer, Integer) -> Integer

但是,当询问以下表达式的类型时,我得到(我期望的)正确结果:

Prelude> :t uncurry (+)
uncurry (+) :: (Num a) => (a, a) -> a

什么会导致这种情况? GHCi 特有吗?

这同样适用于 let add' = (+)

注意:我无法使用编译文件重现该内容

I've been playing with the uncurry function in GHCi and I've found something I couldn't quite get at all. When I apply uncurry to the (+) function and bind that to some variable like in the code below, the compiler infers its type to be specific to Integer:

Prelude> let add = uncurry (+)
Prelude> :t add
add :: (Integer, Integer) -> Integer

However, when ask for the type of the following expression I get (what I expect to be) the correct result:

Prelude> :t uncurry (+)
uncurry (+) :: (Num a) => (a, a) -> a

What would cause that? Is it particular to GHCi?

The same applies to let add' = (+).

NOTE: I could not reproduce that using a compiled file.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

听你说爱我 2024-10-24 04:39:35

这与ghci无关。这是令人恼火的单态限制。如果您尝试编译以下文件:

add = uncurry (+)
main = do
    print $ add (1,2 :: Int)
    print $ add (1,2 :: Double)

您将收到错误。如果扩展:

main = do
    print $ uncurry (+) (1,2 :: Int)
    print $ uncurry (+) (1,2 :: Double)

一切都很好,正如预期的那样。单态性限制拒绝使“看起来像值”(即等号左侧没有参数定义)的东西成为类型类多态,因为这会破坏通常发生的缓存。例如。

foo :: Integer
foo = expensive computation

bar :: (Num a) => a
bar = expensive computation

foo 保证只计算一次(至少在 GHC 中),而 bar 每次被提及时都会被计算。单态性限制旨在通过默认为前一种情况来将您从后一种情况中拯救出来,而这正是您想要的。

如果您只使用该函数一次(或始终使用同一类型),类型推断将负责为您推断正确的类型。在这种情况下,ghci 会通过更快地猜测来做一些稍微不同的事情。但在两种不同类型中使用它可以显示发生了什么。

如有疑问,请使用类型签名(或使用 {-# LANGUAGE NoMonomorphismRestriction #-} 关闭这个糟糕的东西)。

This has nothing to do with ghci. This is the monomorphism restriction being irritating. If you try to compile the following file:

add = uncurry (+)
main = do
    print $ add (1,2 :: Int)
    print $ add (1,2 :: Double)

You will get an error. If you expand:

main = do
    print $ uncurry (+) (1,2 :: Int)
    print $ uncurry (+) (1,2 :: Double)

Everything is fine, as expected. The monomorphism restriction refuses to make something that "looks like a value" (i.e. defined with no arguments on the left-hand side of the equals) typeclass polymorphic, because that would defeat the caching that would normally occur. Eg.

foo :: Integer
foo = expensive computation

bar :: (Num a) => a
bar = expensive computation

foo is guaranteed only to be computed once (well, in GHC at least), whereas bar will be computed every time it is mentioned. The monomorphism restriction seeks to save you from the latter case by defaulting to the former when it looks like that's what you wanted.

If you only use the function once (or always at the same type), type inference will take care of inferring the right type for you. In that case ghci is doing something slightly different by guessing sooner. But using it at two different types shows what is going on.

When in doubt, use a type signature (or turn off the wretched thing with {-# LANGUAGE NoMonomorphismRestriction #-}).

爱*していゐ 2024-10-24 04:39:35

ghci 的扩展默认规则有其魔力。基本上,除其他外,Num 约束默认为 Integer,Floating 约束默认为 Double,否则会出现错误(在这种情况下,由于邪恶的单态性限制)。

There's magic involved in extended defaulting rules with ghci. Basically, among other things, Num constraints get defaulted to Integer and Floating constraints to Double, when otherwise there would be an error (in this case, due to the evil monomorphism restriction).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文