2014-07-13 96 views
15

雖然迭代我的代碼朝着正確的版本,我碰到下面的好奇心就來了:讓 - 重命名功能符碼

{-# LANGUAGE RankNTypes #-} 

module Foo where 

import Data.Vector.Generic.Mutable as M 
import Control.Monad.Primitive 

-- an in-place vector function with dimension 
data DimFun v m r = 
    DimFun Int (v (PrimState m) r -> m()) 

eval :: (PrimMonad m, MVector v r) => DimFun v m r -> v (PrimState m) r -> m() 
eval = error "" 

iterateFunc :: (PrimMonad m, MVector v r) 
      => (forall v' . (MVector v' r) => DimFun v' m r) -> DimFun v m r 
iterateFunc = error "" 

f :: (PrimMonad m, MVector v r) 
     => DimFun v m r 
f = error "" 

iteratedF :: (MVector v r, PrimMonad m) 
      => v (PrimState m) r -> m() 
iteratedF y = 
    let f' = f 
    in eval (iterateFunc f') y 

此代碼不能編譯:

Testing/Foo.hs:87:14: 
    Could not deduce (MVector v0 r) arising from a use of ‘f’ 
    from the context (MVector v r, PrimMonad m) 
     bound by the type signature for 
       iteratedF :: (MVector v r, PrimMonad m) => 
           v (PrimState m) r -> m() 
     at Testing/Foo.hs:(84,14)-(85,39) 
    The type variable ‘v0’ is ambiguous 
    Relevant bindings include 
     f' :: DimFun v0 m r (bound at Testing/Foo.hs:87:9) 
     y :: v (PrimState m) r (bound at Testing/Foo.hs:86:11) 
     iteratedF :: v (PrimState m) r -> m() 
     (bound at Testing/Foo.hs:86:1) 
    In the expression: f 
    In an equation for ‘f'’: f' = f 
    In the expression: let f' = f in eval (iterateFunc f') y 

Testing/Foo.hs:88:26: 
    Couldn't match type ‘v0’ with ‘v'’ 
     because type variable ‘v'’ would escape its scope 
    This (rigid, skolem) type variable is bound by 
     a type expected by the context: MVector v' r => DimFun v' m r 
     at Testing/Foo.hs:88:14-27 
    Expected type: DimFun v' m r 
     Actual type: DimFun v0 m r 
    Relevant bindings include 
     f' :: DimFun v0 m r (bound at Testing/Foo.hs:87:9) 
    In the first argument of ‘iterateFunc’, namely ‘f'’ 
    In the first argument of ‘eval’, namely ‘(iterateFunc f')’ 
Failed, modules loaded: none. 

但是,如果我改變iteratedF

的定義
iteratedF y = eval (iterateFunc f) y 

代碼編譯爲GHC 7.8.2。這個問題不是關於奇怪的簽名或數據類型,它只是這樣的:爲什麼重命名ff'破解代碼?這似乎是我必須成爲一個錯誤。

回答

7

問題當然並不重命名,但到一個新的變量結合。由於iterateFunc是Rank-2,它需要一個多態的參數函數。當然,fv中是多態的,所以可以使用。但是當你編寫f' = f時,不清楚f'應該是什麼類型:與f相同的多態類型,或者某種單形類型,可能取決於編譯器還沒有推導出的iteratedF中另一個類型變量的某些關係。

編譯器默認爲單形選項;正如chi說這是單態限制的錯誤,所以如果你關閉它,你的代碼實際上會編譯。

儘管如此,即使沒有RankNTypes代碼中的單態限制,也會出現同樣的問題,這是完全無法避免的。唯一可靠的解決方案是本地簽名,通常需要ScopedTypeVariables

+2

那麼可怕的單形態限制的另一種情況。 – crockeea

+4

我不認爲重命名不會在純Haskell 98中造成麻煩。考​​慮'let f = show in f 1 ++ f True'。 –

12

禁用單態限制,我可以編譯你的代碼。所以,只需添加

{-# LANGUAGE NoMonomorphismRestriction #-} 

在您的文件的開始。

的原因類型的錯誤是定義

let f' = f 

不使用功能模式(例如f' x y = ...),所以單態限制踢和力f'是單態,而iterateFunc需要一個多態功能。

或者,添加的類型註釋

let f' :: (PrimMonad m, MVector v r) => DimFun v m r 
    f' = f 
+1

奇怪的是,在ghc-7.8中甚至需要'NoMono ...'標誌......我認爲它完全具有單態限制,但顯然這隻適用於頂層或某些東西。 – leftaroundabout

+7

@leftaroundabout我認爲這只是GHCi – bennofs