haskell – 讓重新命名功能中斷程式碼
在將程式碼迭代到正確的版本時,我遇到了以下好奇心:
{-# 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.這個問題不是關於奇怪的簽名或資料型別,只是這樣:為什麼重新命名f到f’打破程式碼?這似乎是對我來說是個錯誤.
問題當然不是重新命名,而是繫結到一個新的變數.由於iterateFunc是Rank-2,它需要一個多型引數函式.當然,f是v中的多型,所以可以使用.但是當你寫f’= f時,不清楚什麼型別f’應該是:與f相同的多型型別或一些單態型別,可能取決於編譯器尚未推出的iteratedF中的另一個型別變數的一些關係.
編譯器預設為單態選項;因為chi說這是單態限制在這裡的錯誤,所以如果你把它關閉你的程式碼實際編譯.
儘管如此,即使在RankNTypes程式碼中沒有單態限制,同樣的問題也可能會發生,但是它不能完全避免.唯一可靠的修復是本地簽名,通常需要ScopedTypeVariables.
程式碼日誌版權宣告:
翻譯自:http://stackoverflow.com/questions/24724738/let-renaming-function-breaks-code