如何在TemplateHaskell函数中定义一个类型并在同一个函数中使用它?

时间:2017-05-22 07:44:31

标签: haskell template-haskell

有没有办法让单个TH函数,定义类型,并使用类型?相关代码如下。 PersonPoly2正在定义makeRecordSplice,然后传递给makeAdaptorAndInstance(来自Opalaye),这也是一个TH函数。

{-# LANGUAGE FlexibleContexts       #-}
{-# LANGUAGE FlexibleInstances      #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses  #-}
{-# LANGUAGE OverloadedStrings      #-}
{-# LANGUAGE TemplateHaskell        #-}

module Lib where

import           Data.Profunctor.Product.TH             (makeAdaptorAndInstance)
import Language.Haskell.TH

makeRecordSplice :: Q [Dec]
makeRecordSplice = [d|
  data PersonPoly2 a b = Person2
    { id :: a 
    , name :: b
    }
  |]

makeRecordAndAdapter :: Q [Dec]
makeRecordAndAdapter = do
  record <- makeRecordSplice
  adapter <- makeAdaptorAndInstance "pPerson2" (mkName "PersonPoly2")
  return $ record ++ adapter


-------------

/home/Projects/scratch/app/Main.hs:26:1: error:
    ‘PersonPoly2’ is not in scope at a reify
Failed, modules loaded: Lib.

1 个答案:

答案 0 :(得分:1)

您遇到的问题是makeRecordSplice需要与实例化的模块不同。此Template-Haskell限制可确保编译时的非循环依赖关系。这是一个恼人的限制,但不是太难以四处走动。这是你可以做到的一种方式:

{-# LANGUAGE FlexibleContexts       #-}
{-# LANGUAGE FlexibleInstances      #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses  #-}
{-# LANGUAGE OverloadedStrings      #-}
{-# LANGUAGE TemplateHaskell        #-}

module Main where

import           Data.Profunctor.Product.TH (makeAdaptorAndInstance)
import           Language.Haskell.TH
import           Lib                        (makeRecordSplice)


$(makeRecordSplice)
$(makeAdaptorAndInstance "pPerson2" (mkName "PersonPoly2"))

main :: IO ()
main = undefined
{-# LANGUAGE FlexibleContexts       #-}
{-# LANGUAGE FlexibleInstances      #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses  #-}
{-# LANGUAGE OverloadedStrings      #-}
{-# LANGUAGE TemplateHaskell        #-}

module Lib where

import           Data.Profunctor.Product.TH (makeAdaptorAndInstance)
import           Language.Haskell.TH

makeRecordSplice :: Q [Dec]
makeRecordSplice = [d|
  data PersonPoly2 a b = Person2
    { id :: a
    , name :: b
    }
  |]

您显然可以为makeAdaptorAndInstance "pPerson2" (mkName "PersonPoly2")创建一个别名并将其隐藏在Lib中,您只是不能在同一模块中依赖另一个接头。

希望这有帮助! : - )