模板Haskell编译错误

模板Haskell编译错误,haskell,template-haskell,hlist,Haskell,Template Haskell,Hlist,考虑以下代码: {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE NoMonomorphismRestriction #-} import Data.HList.GhcSyntax((.!.),(.=.),(.*.)) import Data.HList.Record(emptyRecord) import Data.HList.TypeCastGeneric1 import Data.HList.TypeEqGeneric1 import Data.

考虑以下代码:

{-# 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)

我发现给顶级函数类型签名可以解决任何问题。请参阅下面的代码:

{-# LANGUAGE TemplateHaskell #-}

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

  f = [| (\x r -> (r .!. x)) |]

添加了f2的定义后,您是否在任何地方使用它?如果没有,那么如果给
f2
一个显式的类型注释是否有效?@DanielWagner:使用
f2
似乎有帮助。然而,我发现了其他问题。请看一个不涉及HList的问题的例子。@DanielWagner:再想想,也许这个问题是在转移注意力,尽管它可能是相关的。我已经找到了一个解决办法,并把它作为我自己问题的答案,它不是理想的,但对我的问题是可行的解决方案。
{-# 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)