2011-10-05 47 views
10

我今天在Haskell遇到了一件令人沮喪的東西Haskell let-expression中的奇怪類型錯誤 - 問題是什麼?

這裏發生了什麼:

  1. 我寫在ghci中的功能,並給它一個類型簽名
  2. ghci的抱怨型
  3. 我刪除了類型簽名
  4. ghci的接受功能
  5. 我檢查了推斷類型
  6. 推斷類型與我試圖給它的類型完全相同
  7. 我很心疼
  8. 我發現我可以重現該問題在任何鬆懈表達
  9. 咬牙切齒的;決定在SO

嘗試與專家進行磋商,以與類型簽名定義函數:

Prelude Control.Monad> let myFilterM f m = do {x <- m; guard (f x); return x} :: (MonadPlus m) => (b -> Bool) -> m b -> m b 

<interactive>:1:20: 
    Inferred type is less polymorphic than expected 
     Quantified type variable `b' is mentioned in the environment: 
     m :: (b -> Bool) -> m b -> m b (bound at <interactive>:1:16) 
     f :: (m b -> m b) -> Bool (bound at <interactive>:1:14) 
     Quantified type variable `m' is mentioned in the environment: 
     m :: (b -> Bool) -> m b -> m b (bound at <interactive>:1:16) 
     f :: (m b -> m b) -> Bool (bound at <interactive>:1:14) 
    In the expression: 
      do { x <- m; 
       guard (f x); 
       return x } :: 
      (MonadPlus m) => (b -> Bool) -> m b -> m b 
    In the definition of `myFilterM': 
     myFilterM f m 
        = do { x <- m; 
          guard (f x); 
          return x } :: 
         (MonadPlus m) => (b -> Bool) -> m b -> m b 

中定義的功能沒有類型簽名,檢查推斷的類型:

Prelude Control.Monad> let myFilterM f m = do {x <- m; guard (f x); return x} 
Prelude Control.Monad> :t myFilterM 
myFilterM :: (MonadPlus m) => (b -> Bool) -> m b -> m b 

用於極大的利好作用 - 一切正常:

Prelude Control.Monad> myFilterM (>3) (Just 4) 
Just 4 
Prelude Control.Monad> myFilterM (>3) (Just 3) 
Nothing 

我最好的猜測,這是怎麼回事:
類型註釋不知何故沒有很好地讓表達式工作,當有一個do-block的時候。

獎勵積分:
是有標準的Haskell分佈做了這樣的功能?我很驚訝,filterM做了非常不同的事情。

+0

類型註釋適用於定義的RHS,而不是'myFilterM',所以你應該說'::(MonadPlus m)=> m b'。這就是爲什麼錯誤信息中'm'和'f'的類型很奇怪。但是我仍然得到了「推斷類型的多態性比預期的更少」的錯誤信息(雖然有更明智的類型),我不知道是什麼原因造成的。 – dave4420

+0

@ dave4420你也使用GHC 6. *?他們在GHC 7中編寫了一個新的類型推斷引擎;也許這是一個錯誤。 – fuz

+0

@FUZxxl那是GHC 6.12.1。我剛剛用GHC 7.0.3試了一下,我得到了兩條錯誤消息,而不是一條,都沒有提到多態性。可能是GHC 7拒絕推斷'myFilterM'的參數類型。 – dave4420

回答

9

問題是類型運算符的優先級(::)。你試圖描述的myFilterM類型,但是你實際上做的是這樣的:

ghci> let myFilterM f m = (\ 
     do {x <- m; guard (f x); return x} \ 
     :: \ 
     (MonadPlus m) => (b -> Bool) -> m b -> m b)\ 
    ) 

你看到的問題(插入可讀性而已,不合法的ghci的語法反斜槓)?我得到了同樣的問題像

ghci> let f x = x + 1 :: (Int -> Int) 
<interactive>:1:15: 
    No instance for (Num (Int -> Int)) 
     arising from the literal `1' 
    Possible fix: add an instance declaration for (Num (Int -> Int)) 
    In the second argument of `(+)', namely `1' 
    In the expression: x + 1 :: Int -> Int 
    In an equation for `f': f x = x + 1 :: Int -> Int 

一些簡單的解決方案是將類型簽名附加到適當的元素:

ghci> let f :: Int -> Int ; f x = x + 1 
ghci> let myFilterM :: (MonadPlus m) => (b -> Bool) -> m b -> m b; myFilterM f m = do {x <- m; guard (f x); return x} 

而對於加分,你要mfilterhoogle is your friend)。

+0

謝謝!我無法相信在使用ghci之前我從來沒有碰到過這個。 –

1

我不知道是什麼樣的,你使用的編譯器,但我的平臺上(GHC 7.0.3),我得到一個簡單的類型不匹配:

$ ghci 
GHCi, version 7.0.3: http://www.haskell.org/ghc/ :? for help 
Loading package ghc-prim ... linking ... done. 
Loading package integer-gmp ... linking ... done. 
Loading package base ... linking ... done. 
Loading package ffi-1.0 ... linking ... done. 
Prelude> :m +Control.Monad 
Prelude Control.Monad> let myFilterM f m = do {x <- m; guard (f x); return x} :: (MonadPlus m) => (b -> Bool) -> m b -> m b 

<interactive>:1:30: 
    Could not deduce (t1 ~ ((b1 -> Bool) -> m1 b1 -> m1 b1)) 
    from the context (MonadPlus m) 
     bound by the inferred type of 
       myFilterM :: MonadPlus m => t -> t1 -> (b -> Bool) -> m b -> m b 
     at <interactive>:1:5-100 
    or from (MonadPlus m1) 
     bound by an expression type signature: 
       MonadPlus m1 => (b1 -> Bool) -> m1 b1 -> m1 b1 
     at <interactive>:1:21-100 
     `t1' is a rigid type variable bound by 
      the inferred type of 
      myFilterM :: MonadPlus m => t -> t1 -> (b -> Bool) -> m b -> m b 
      at <interactive>:1:5 
    In a stmt of a 'do' expression: x <- m 
    In the expression: 
     do { x <- m; 
      guard (f x); 
      return x } :: 
      MonadPlus m => (b -> Bool) -> m b -> m b 
    In an equation for `myFilterM': 
     myFilterM f m 
      = do { x <- m; 
       guard (f x); 
       return x } :: 
       MonadPlus m => (b -> Bool) -> m b -> m b 

<interactive>:1:40: 
    Could not deduce (t ~ ((m1 b1 -> m1 b1) -> Bool)) 
    from the context (MonadPlus m) 
     bound by the inferred type of 
       myFilterM :: MonadPlus m => t -> t1 -> (b -> Bool) -> m b -> m b 
     at <interactive>:1:5-100 
    or from (MonadPlus m1) 
     bound by an expression type signature: 
       MonadPlus m1 => (b1 -> Bool) -> m1 b1 -> m1 b1 
     at <interactive>:1:21-100 
     `t' is a rigid type variable bound by 
      the inferred type of 
      myFilterM :: MonadPlus m => t -> t1 -> (b -> Bool) -> m b -> m b 
      at <interactive>:1:5 
    The function `f' is applied to one argument, 
    but its type `t' has none 
    In the first argument of `guard', namely `(f x)' 
    In a stmt of a 'do' expression: guard (f x) 
Prelude Control.Monad> 

我想這個問題在於這樣一個事實,即::沒有達到論據。這個小變化(注意單獨的類型聲明)

let myFilterM f m = do {x <- m; guard (f x); return x}; myFilterM :: (MonadPlus m) => (b -> Bool) -> m b -> m b 

運行沒有問題。它可能與GHC 7中的新類型檢查器有關。

3

這可能只是類型註釋語法和綁定優先級的問題。如果你寫你的例子,

let myFilterM :: (MonadPlus m) => (b -> Bool) -> m b -> m b; myFilterM f m = do {x <- m; guard (f x); return x} 

然後GHCi會給你一個高五,併發送你的方式。