。局所的に名前のない表現では、バインドされた変数はde Bruijnインデックスを使用して表され、バインドされていない変数は名前を使用して表されます。これは、アルファ等価性やキャプチャを避ける代用などの場合には、 "これは変数にバインドされていますか?"非常に簡単になります。
通常、ローカルで名前のない表現は、サーフェス構文ツリー上のスコープチェック操作の出力です。私たちは、代わりにBool
の確認期間を生成するために@HNTW's answerからコードを調整することができます
data Scoped a = SVar a
| SLet (Scoped a) (Scope() Scoped a) -- The expression being let-bound, and the subexpression with the new variable in scope
| SLit Number
| SSub (Scoped a)
| SSum (Scoped a) (Scoped a)
| SMul (Scoped a) (Scoped a)
| SIf (Scoped a) (Scoped a) (Scoped a)
deriving (Functor, Foldable, Traversable)
instance Applicative Scoped where
pure = SVar
(<*>) = ap
instance Monad Scoped where
return = SVar
SVar a >>= g = g a
SLet expr scope >>= g = SLet (expr >>= g) (scope >>>= g)
SLit x >>= g = SLit x
SSub x >>= g = SSub (x >>= g)
SSum x y >>= g = SSum (x >>= g) (y >>= g)
SMul x y >>= g = SMul (x >>= g) (y >>= g)
SIf cond t f >>= g = SIf (cond >>= g) (t >>= g) (f >>= g)
scoped :: Expr -> Scoped Char
scoped (Var x) = SVar x
scoped (Let name expr sub) = SLet (scope expr) (abstract1 name $ scoped sub)
scoped (Lit x) = SLit x
scoped (Sub s) = SSub (scoped s)
scoped (Sum x y) = SSum (scoped x) (scoped y)
scoped (Mul x y) = SMul (scoped x) (scoped y)
scoped (If cond t f) = SIf (scoped cond) (scoped t) (scoped f)
bound
名前a
の「コンテナ」として表現を表示します。 Monad
インスタンスは置換を実行します((>>=) :: Scoped a -> (a -> Scoped b) -> Scoped b
はa
という名前の関数マッピング名をScoped b
に移植して移植します)。bound
ライブラリでは、この置換操作を使用して、サブ式の変数をバインドして新しいサブ表現を生成するabstract1
などのツールを実装しますローカルで名前のない形式で。
(別のExpr
タイプを削除してパーサーの出力として直接Scoped Char
を生成することは不合理ではありません。)
Scoped
のFoldable
およびTraversable
インスタンスでは、式内のすべてのバインドされていない変数を見つけることができます。
unboundVariables :: Scoped a -> [a]
unboundVariables = toList
bound
のisClosed
コンビネータは、あなたが望んでいただけで何が行われます。式は任意の自由変数を持っている場合、それはFalse
を返します。
スコープの下で歩いて、あなたが特定の変数が結合した、または自由されている場合、あなたはどちらかできVar
のB
とF
コンストラクタ上のパターンマッチ、またはthe supplied Prism
sを使用する知っている必要があり、場合:
isBound :: Var b f -> Bool
isBound = is _B
bound
の詳細については、this blog postまたはthese slidesを参照してください。
IMHOこのチェックは、解析後、より高いレベルで行われます。 –
ええ、私はそう思います、少なくとも私はそれをもっと簡単にするでしょう。 – iIllumination
あなたの 'Let'コンストラクタが間違って設定されていると思います。 'e'の' let x = e1'の '='の左側にあるものは、任意の式ではなく、_name_(またはより一般的には_pattern)です。 'let(if foo then bar else baz)= x in y'は意味をなさない! –