gpt4 book ai didi

dsl - 如何在 PureScript 中实现 "finally tagless"类型类的 Monadic 实例?

转载 作者:行者123 更新时间:2023-12-03 03:04:16 24 4
gpt4 key购买 nike

我正在致力于使用“最终无标签”风格在 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 ),它可以用作嵌入式语言并解释(或运行)以评估为字符串(或者,您可以对结构进行静态分析,而不是转向将其转化为字符串)。

原则上,还可以有一个副作用示例,它实际上与文件系统交互,但可以“解释”完全相同的嵌入式语言。我想为此使用 purescript-node-fs ,这意味着在某处接受 Eff (fs::FS, err::EXCEPTION | eff)

我的问题是 - 如何实际实现“真实”、有效的实例?您是否必须更改 cdlscat 的签名?或者您能否以某种方式评估 Eff 中的整个 monad,以便这些函数不需要在其签名中携带 Eff

最佳答案

因为您想为 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

关于dsl - 如何在 PureScript 中实现 "finally tagless"类型类的 Monadic 实例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42166789/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com