2012-08-27 62 views
2

考慮下面的代碼:模板哈斯克爾編譯錯誤

{-# LANGUAGE TemplateHaskell #-} 
{-# LANGUAGE NoMonomorphismRestriction #-} 

import Data.HList.GhcSyntax((.!.),(.=.),(.*.)) 
import Data.HList.Record(emptyRecord) 
import Data.HList.TypeCastGeneric1 
import Data.HList.TypeEqGeneric1 
import Data.HList.Label5 

data Hello1 = Hello1 
data Hello2 = Hello2 

record = (Hello1 .=. "Hello1") .*. (Hello2 .=. "Hello2") .*. emptyRecord 

f1 = $([| (\r1 -> (r1 .!. Hello1)) |]) 

main = print $ f1 record 

編譯沒有問題,並打印出「Hello1」預期。

然而,添加以下行(GHC 7.4.1)給出一個編譯錯誤:

f2 = $([| (\r2 -> (r2 .!. Hello2)) |]) 

給出的錯誤是:

error.hs:16:1: 
    Could not deduce (Data.HList.Record.HasField Hello2 r0 v0) 
     arising from the ambiguity check for `main' 
    from the context (Data.HList.Record.HasField Hello2 r v) 
     bound by the inferred type for `main': 
       Data.HList.Record.HasField Hello2 r v => IO() 
     at error.hs:(16,1)-(20,38) 
    Possible fix: 
     add an instance declaration for 
     (Data.HList.Record.HasField Hello2 r0 v0) 
    When checking that `main' 
     has the inferred type `forall r v. 
          Data.HList.Record.HasField Hello2 r v => 
          IO()' 
    Probable cause: the inferred type is ambiguous 

error.hs:16:1: 
    Could not deduce (Data.HList.Record.HasField Hello2 r0 v0) 
     arising from the ambiguity check for `f1' 
    from the context (Data.HList.Record.HasField Hello2 r v) 
     bound by the inferred type for `f1': 
       Data.HList.Record.HasField Hello2 r v => 
       Data.HList.Record.Record 
        (Data.HList.HListPrelude.HCons 
         (Data.HList.Record.LVPair Hello1 [Char]) 
         (Data.HList.HListPrelude.HCons 
         (Data.HList.Record.LVPair Hello2 [Char]) 
         Data.HList.HListPrelude.HNil)) 
       -> [Char] 
     at error.hs:(16,1)-(20,38) 
    Possible fix: 
     add an instance declaration for 
     (Data.HList.Record.HasField Hello2 r0 v0) 
    When checking that `f1' 
     has the inferred type `forall r v. 
          Data.HList.Record.HasField Hello2 r v => 
          Data.HList.Record.Record 
           (Data.HList.HListPrelude.HCons 
            (Data.HList.Record.LVPair Hello1 [Char]) 
            (Data.HList.HListPrelude.HCons 
            (Data.HList.Record.LVPair Hello2 [Char]) 
            Data.HList.HListPrelude.HNil)) 
          -> [Char]' 
    Probable cause: the inferred type is ambiguous 

爲什麼添加f2線導致編譯錯誤?

注意:模板Haskell部分在這裏可能看起來很愚蠢,但它們是更復雜的模板Haskell的簡化,它可以在元組上工作。我發佈了我可以構建的最簡單的示例,但仍然顯示錯誤。我意識到在這種情況下刪除模板Haskell解決了這個問題,但這不是我真正的代碼中的一個選項。

編輯:

此外,以下編譯失敗。爲什麼是這種情況:

{-# LANGUAGE TemplateHaskell #-} 
{-# LANGUAGE NoMonomorphismRestriction #-} 

import Data.HList.GhcSyntax((.!.),(.=.),(.*.)) 
import Data.HList.Record(emptyRecord) 
import Data.HList.TypeCastGeneric1 
import Data.HList.TypeEqGeneric1 
import Data.HList.Label5 

data Hello1 = Hello1 
data Hello2 = Hello2 
data Hello3 = Hello3 

record1 = (Hello1 .=. "Hello1") .*. (Hello2 .=. "Hello2") .*. emptyRecord 
record2 = (Hello1 .=. "Hello1") .*. (Hello2 .=. "Hello2") .*. (Hello3 .=. "Hello3") .*. emptyRecord 

f1 = $([| (\r1 -> (r1 .!. Hello1)) |]) 

main = print $ (f1 record1, f1 record2) 
+0

添加定義'f2'後,你使用它的任何地方?如果不是,如果給'f2'一個明確的類型註解,它是否工作? –

+0

@DanielWagner:使用'f2'似乎有所幫助。但是,我發現了其他問題。請參閱http://stackoverflow.com/questions/12144250/template-haskell-compile-error-when-calling-with-different-parameters關於不涉及HList的問題的示例。 – Clinton

+0

@DanielWagner:再想一想,或許這個問題是一個紅鯡魚,儘管它可能是相關的。我找到了一個解決方法,並將其作爲我自己問題的答案,這不是理想的,但對我的問題可行的解決方案。 – Clinton

回答

1

我發現給你的頂級功能類型簽名可以修復任何問題。請參見下面的代碼:

{-# LANGUAGE TemplateHaskell #-} 

module X where 
    import Data.HList.GhcSyntax((.!.)) 

    f = [| (\x r -> (r .!. x)) |] 
{-# LANGUAGE TemplateHaskell #-} 
{-# LANGUAGE NoMonomorphismRestriction #-} 
{-# LANGUAGE FlexibleContexts #-} 

import Data.HList.GhcSyntax((.!.),(.=.),(.*.)) 
import Data.HList.Record(emptyRecord) 
import Data.HList.TypeCastGeneric1 
import Data.HList.TypeEqGeneric1 
import Data.HList.Label5 
import X 
import Data.HList.Record (HasField) 

data Hello1 = Hello1 
data Hello2 = Hello2 
data Hello3 = Hello3 

record1 = (Hello1 .=. "Hello1") .*. (Hello2 .=. "Hello2") .*. emptyRecord 
record2 = (Hello1 .=. "Hello1") .*. (Hello2 .=. "Hello2") .*. (Hello3 .=. "Hello3") .*. emptyRecord 

g1 :: (HasField Hello1 a b) => a -> b -- Type signature here 
g1 = $(f) Hello1 

g2 :: (HasField Hello2 a b) => a -> b -- Type signature here 
g2 = $(f) Hello2 

main = print $ (g1 record1, g2 record1, g1 record2, g2 record2)