我正在使用"最终无标记"在PureScript中实现嵌入式DSL。样式。回购可以在https://github.com/afcondon/purescript-finally-tagless-ex
找到这就是问题所在。给出一个非常简化的文件系统的抽象定义:
class (Monad m) <= MonadFileSystem m where
cd :: FilePath -> m Unit
ls :: m (Array (Tuple FilePath FileType))
cat :: Array FilePath -> m String
可以很容易地提供一个这样的实现(https://github.com/afcondon/purescript-finally-tagless-ex/blob/master/MonadicEx/src/FakeFileSystem.purs),它可以用作嵌入式语言并解释(或运行)以作为字符串进行求值(或者你也可以对结构进行静态分析)把它变成一个字符串)。
原则上,人们还可以有一个副作用的例子,它实际上会与文件系统进行交互但是可以解释&#34;完全相同的嵌入式语言。我想使用purescript-node-fs
来表示接受Eff (fs :: FS, err :: EXCEPTION | eff)
某处。
我的问题是 - 如何实际实现&#34;真实&#34;,有效的实例?您是否需要更改cd
,ls
和cat
的签名?或者你能以某种方式评估Eff
中的整个monad,以便这些函数不需要在签名中携带Eff
吗?
答案 0 :(得分:3)
因为你想为Eff
创建一个实例,所以这里有一点问题,因为我们需要在类型中包含行,但正如你可能发现的那样,编译器在这种情况下会抱怨实例头。
一种选择是使用newtype
:
import Prelude
import Control.Monad.Eff (Eff)
import Control.Monad.Eff.Exception (EXCEPTION)
import Data.Tuple (Tuple)
import Node.FS (FS)
import Node.Path (FilePath)
type FileType = String
class (Monad m) <= MonadFileSystem m where
cd :: FilePath -> m Unit
ls :: m (Array (Tuple FilePath FileType))
cat :: Array FilePath -> m String
newtype FSEff eff a = FSEff (Eff (fs :: FS, err :: EXCEPTION | eff) a)
runFSEff :: forall eff a. FSEff eff a -> Eff (fs :: FS, err :: EXCEPTION | eff) a
runFSEff (FSEff fse) = fse
derive newtype instance functorFSEff :: Functor (FSEff eff)
derive newtype instance applyFSEff :: Apply (FSEff eff)
derive newtype instance applicativeFSEff :: Applicative (FSEff eff)
derive newtype instance bindFSEff :: Bind (FSEff eff)
derive newtype instance monadFSEff :: Monad (FSEff eff)
instance monadFileSystemFSEff :: MonadFileSystem (FSEff eff) where
cd _ = pure unit
ls = pure []
cat _ = pure "meow"
但是也可以使用函数依赖来完成一些技巧,您可以将行指定为相等约束。这编译,但我还没有尝试使用这种技术,所以我不能保证它肯定在更大的背景下工作:
import Prelude
import Control.Monad.Eff (Eff)
import Control.Monad.Eff.Exception (EXCEPTION)
import Data.Tuple (Tuple)
import Node.FS (FS)
import Node.Path (FilePath)
type FileType = String
class (Monad m) <= MonadFileSystem m where
cd :: FilePath -> m Unit
ls :: m (Array (Tuple FilePath FileType))
cat :: Array FilePath -> m String
instance monadFileSystemEff :: EffectRowEquals r (fs :: FS, err :: EXCEPTION | eff) => MonadFileSystem (Eff r) where
cd _ = pure unit
ls = pure []
cat _ = pure "meow"
-- This should probably go in `purescript-type-equality`:
class EffectRowEquals (a ∷ # !) (b ∷ # !) | a → b, b → a where
toER ∷ ∀ r. r a → r b
fromER ∷ ∀ r. r b → r a
instance reflER ∷ EffectRowEquals r r where
toER er = er
fromER er = er