2017-02-10 7 views
3

私は、「最終的なタグなし」スタイルを使用してPureScriptに埋め込み型DSLを実装しようとしています。レポはhttps://github.com/afcondon/purescript-finally-tagless-exPureScriptで「最終的にタグなし」typeclassのMonadicインスタンスを実装する方法は?

にあります。問題があります。非常に単純化されたファイルシステムの抽象定義を考える:

class (Monad m) <= MonadFileSystem m where 
    cd :: FilePath  -> m Unit 
    ls ::     m (Array (Tuple FilePath FileType)) 
    cat :: Array FilePath -> m String 

一つ簡単に文字列として評価するための組み込み言語として使用され、解釈(または実行する)ことができるように、この1(https://github.com/afcondon/purescript-finally-tagless-ex/blob/master/MonadicEx/src/FakeFileSystem.purs)として実装を提供することができます(あるいは、文字列に変換するのではなく、静的解析を行うこともできます)。

原則として、実際にはファイルシステムとやりとりするが、同じ埋め込み言語を正確に「解釈」できる副作用の例を持つこともできます。私はを受け入れることを意味するpurescript-node-fsを使用したいと思います。

私の質問です。実際に "本当の"効果のあるインスタンスを実際に実装するにはどうすればよいですか? cdlscatの署名を変更する必要がありますか?またはEffのモナド全体を何らかの形で評価して、それらの関数がEffを署名に入れる必要がないようにすることはできますか?

答えて

3

Effのインスタンスを作成したいので、型に行を含める必要があるため、少し問題があります。しかし、おそらく見つけたように、コンパイラはこの場合インスタンスの頭について苦情を言います。

1つのオプションは、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" 

しかし、あなたが代わりに等式制約のような行を指定することができる機能の依存関係を、使用して行うことができるいくつかの策略もあります。これはコンパイルされますが、実際にはこのテクニックを使用しようとはしませんでしたので、大きな文脈で確実に動作することを保証することはできません:

+0

本当に詳細な回答がありがとうございます。前者は副作用のみの状況ではうまく動作しますが、多くの状況で必要となる現在の作業ディレクトリのようなコンテキストを持つような方法で作成するのは難しいです。私は、FakeFSインスタンスのZipperの例に似た何かのハッキングを試みましたが、それはすべての素晴らしいnewtypeの派生を破ります。 2番目の解決策は本当に素敵で表現力がありますが、AbstractFileSystemと同じ場所に配置されていない限り、孤立したインスタンスエラーが発生するようです(偽ですか? –

+0

孤児のエラーを避けるために 'MonadFileSystem'と一緒に後者を定義する必要があるのは事実です(別の孤立していない場所は' Eff'を持つモジュールにあります。あなたのフォローアップの質問では、とにかくcwdなどを維持するために 'Eff'の周りに' StateT'が必要なように聞こえるでしょう。この場合、おそらく孤児の問題を避ける 'newtype'ルートに行くでしょうあまりにも。 –

関連する問題