什么使`:t`与GHCi中的表达区别开来

时间:2014-02-16 20:50:42

标签: haskell

我想制作一个产生Maybe a的玩具功能,然后抬起show使其成为Maybe String,但结果对我来说很奇怪:

λ> :t liftM show . Just
liftM show . Just :: Show a1 => a1 -> Maybe String
λ> liftM show . Just $ 10
Just "10"
λ> let f = liftM show . Just
λ> f 10

<interactive>:9:3:
    No instance for (Num ()) arising from the literal `10'
    Possible fix: add an instance declaration for (Num ())
    In the first argument of `f', namely `10'
    In the expression: f 10
    In an equation for `it': it = f 10
λ> :t f
f :: () -> Maybe String
λ> let g = liftM show . Just :: (Show a) => a -> Maybe String
λ> :t g
g :: () -> Maybe String
λ> let h = liftM show . Just :: Int -> Maybe String
λ> :t h
h :: Int -> Maybe String

我想它与类型推断有关,但我真的不知道发生了什么:

  • 神秘的()来自哪里?
  • 为什么GHCi没有抱怨模棱两可?

1 个答案:

答案 0 :(得分:7)

姆-duuum!

dreaded monomorphism restriction的下一个受害者。

这是怎么回事:对于看起来像“常量变量”的定义(在其他语言也可能使用的意义上,即不是函数类型),如f = ...,假设你希望它确实表现得像一个常数(CAF,确切地说)。这意味着,它不能是多态的,因为对于参数多态,基本上有一个函数的额外隐式参数(类型a1应该是的信息)。

要实现这个实际的常量,ghci defaults这个类型变量,它认为最不合适的任何特定类型。这里,唯一的约束是Show;最简单的类型是()

解决这个问题的“正确”方法是关闭单态限制:

  

前奏&GT; :set -XNoMonomorphismRestriction
  前奏&GT; :m + Control.Monad
  Prelude Control.Monad&gt;让f = liftM显示。只是
  Prelude Control.Monad&gt; f 10
  只是“10”左

或者,您可以像在实际的源文件中一样,在ghci中为标识符提供适当的签名:

  

Prelude Control.Monad&gt;让g :: Show a =&gt; a - &gt;也许String; g = liftM显示。只是
  Prelude Control.Monad&gt; g 10
  只是“10”左

仅在=的RHS上执行此操作不起作用,因为单态限制仅在解析后启动并默认输出变量(除非在h中有首先没有变量,因为你给了RHS一个单态签名。

你可以做的另一件事,只是给函数一个显式参数,然后单态性限制根本不适用。即,将其写成非点免费:

  

Prelude Control.Monad&gt;让我a = liftM显示$只是一个   Prelude Control.Monad&gt;我10   只是“10”左