是否可以使用Free在DSL中实现多态函数

Bro*_*nie 6 dsl haskell free-monad

我正在使用Free Monads构建一个小型DSL.

我希望能够在我的DSL中拥有多态功能.

我想要构建的一个例子是:

{-# LANGUAGE TemplateHaskell #-}

import           Control.Monad.Free.Church

data Queue a = Queue a

data MyDsl next =
  NewQueue (Queue a -> next) |
  WriteToQueue (Queue a) a next

makeFree ''MyDsl

testProgram :: F MyDsl
testProgram = do
  (intQueue :: Queue Int) <- newQueue
  (charQueue :: Queue Char) <- newQueue
  writeToQueue intQueue 1
  writeToQueue charQueue 'c'
Run Code Online (Sandbox Code Playgroud)

我编码它的方式我得到的Not in scope: type variable ‘a’ 错误是有道理的.有没有办法在使用Free的DSL中拥有多态函数?

对于背景,我想这样做的原因是我可以拥有一个在幕后使用TQueue的生产解释器和一个使用内存数据结构进行测试的测试解释器.

Cir*_*dec 11

您可以使用GADT代表您的DSL

{-# LANGUAGE GADTs #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE DeriveFunctor #-}

data Queue a = Queue a

data MyDsl next where
  NewQueue :: (Queue a -> next) -> MyDsl next
  WriteToQueue :: (Queue a) -> a -> next -> MyDsl next

deriving instance Functor MyDsl
Run Code Online (Sandbox Code Playgroud)

makeFree不能也makeFreeCon不能生成自由的多态monadic动作MyDsl.你需要自己写.

{-# LANGUAGE FlexibleContexts #-}

import Control.Monad.Free.Class

newQueue :: (MonadFree MyDsl m) => m (Queue a)
newQueue = wrap $ NewQueue return

writeToQueue :: (MonadFree MyDsl m) => Queue a -> a -> m ()
writeToQueue q v = liftF $ WriteToQueue q v ()
Run Code Online (Sandbox Code Playgroud)

现在您可以编写测试程序了.

{-# LANGUAGE ScopedTypeVariables #-}

import Control.Monad.Free.Church

-- testProgram can have a more general type
-- testProgram :: (MonadFree MyDsl m) => m ()
testProgram :: F MyDsl ()
testProgram = do
  (intQueue :: Queue Int) <- newQueue
  (charQueue :: Queue Char) <- newQueue
  writeToQueue intQueue 1
  writeToQueue charQueue 'c'
Run Code Online (Sandbox Code Playgroud)

如果参数化队列类型,您可能会发现DSL更容易编写多个解释器.如果这样做,您将需要类型系列或函数依赖项来根据monad的类型确定队列的类型.

data MyDsl q next where
  NewQueue :: (q a -> next) -> MyDsl next
  WriteToQueue :: (q a) -> a -> next -> MyDsl next
Run Code Online (Sandbox Code Playgroud)