2012-08-27 151 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)