2016-10-16 3 views
1

私はExpr型の値をTermに変換するのに役立つモナド関数を持っています。署名は、私はトラブルが一般的であるケースを処理する必要がありアイテムリストのモナディック表現を一般化する

fromDM :: (Name -> CompilerM Term) -> Expr -> CompilerM Term

です。私は今、私は一般的なルール、すなわちTuple esでこれを代用したい

import Control.Monad.State 

type CompilerM = State Incr 

newtype Incr = Incr Int deriving (Show) 

generateNameM :: CompilerM Name 
generateNameM = state $ \i -> 
    let Incr y = i 
     j  = (+1) y 
    in (Name j, Incr j) 

data Expr = Tuple [Expr] 
data Name = Name Int 
data Term = Let Name [Name] Term 

fromDM :: (Name -> CompilerM Term) -> Expr -> CompilerM Term 
fromDM k expr = case expr of 
    Tuple [e1, e2]   -> do 
    x <- generateNameM 
    t' <- k x 
    fromDM (\z1 -> fromDM (\z2 -> pure $ Let x [z1, z2] t') e2) e1 

    Tuple [e1, e2, e3]  -> do 
    x <- generateNameM 
    t' <- k x 
    fromDM (\z1 -> fromDM (\z2 -> fromDM (\z3 -> pure $ Let x [z1, z2, z3] t') e3) e2) e1 

    Tuple [e1, e2, e3, e4] -> do 
    x <- generateNameM 
    t' <- k x 
    fromDM (\z1 -> fromDM (\z2 -> fromDM (\z3 -> fromDM (\z4 -> return $ Let x [z1, z2, z3, z4] t') e4) e3) e2) e1 

すべての個々のソリューションの実装を書き留めることができます。私はこれがfoldlMまたはfoldrMのいずれかで実行可能でなければならないと感じています。しかし、私はこれをどうやってやり遂げるのかちょっと固まっています。だから、どのように表現の任意のリストで動作するこの変換の一般的なルールを書くのですか?

+0

[withCStringのような連鎖機能に方法はありますか?]の可能な重複(http://stackoverflow.com/questions/37379984/is-there-a-way-to-chain-functions-like- withcstring) – Cactus

+1

その質問はどのように重複していますか?私は残念なことに、そこにある質問や答えに自分の質問をマッピングすることはできません。 – wirrbel

+0

関連する種類に関する詳細情報が役立ちます。 – chepner

答えて

2

さて、私はContについてよく知らないので、私はこの質問に近づいたときに思考過程を概説しましょう。私がやってみたかった最初の事は、このように、Tupleの内容に依存したコードのビットのみを引き出すことでした:

fromDM k expr = case expr of 
    Tuple es -> do 
     x <- generateNameM 
     t' <- k x 
     letExprs x t' es 

letExprs x t' [e1, e2] = fromDM (\z1 -> fromDM (\z2 -> pure $ Let x [z1, z2] t') e2) e1 
-- etc. 

それは、任意の長さのリストに作業できるように、私たちは、抽象letExprsしたいです。問題を書き留めたので、Feynmanプロトコルの次のステップはThink Very Hardです。だから私は別のケースで非常にハードを見た。それはリストの各コンスセルがfromDMへの呼び出しに変わったように私に見えた。基本ケースでは、Letをさまざまなリストに適用しました。さまざまなリストを次のようにアキュムレータに貼り付けることができます:

fromDM k expr = case expr of 
    Tuple es -> do 
     x <- generateNameM 
     t' <- k x 
     letExprs x t' [] es 

letExprs x t' vars [] = pure $ Let x (reverse vars) t' 
letExprs x t' vars (e:es) = fromDM (\z -> letExprs x t' (z:vars) es) e 

これはすでにかなりうまく見えます。あなたが折り畳みにしたい場合(通常の理由でうまくいきます:あなたが誤って再帰パターンを台無しにすることはできませんし、読者はあなたが何かトリッキーなことをしていないことを知っています)

fromDM k expr = case expr of 
    Tuple es -> do 
     x <- generateNameM 
     t' <- k x 
     foldr (\e k vars -> fromDM (\z -> k (z:vars)) e) 
       (\vars -> pure $ Let x (reverse vars) t') 
       es 
+0

素晴らしいですね。 'Expr'はたった一つのケースしか持たないので少し単純化することができます。' fromDM k(Tuple es)= do ... ' – Yawar

+1

@ Yawarおそらくこれはもっと複雑なデータ型のコレクションを減らしたものです私ができる限りどこでも元のコードスタイルを維持します。 –