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行を追加するとコンパイルエラーになるのはなぜですか?

注: Template Haskell のパーツはここではばかげているように見えるかもしれませんが、タプルで機能するより複雑な Template 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)
4

1 に答える 1

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)
于 2012-08-27T15:52:01.330 に答える