作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
如何使用 SYB(或其他一些 Haskell 泛型包)在 Reader
中编写转换使用 local
的 monad修改子计算的环境? GenericM
的类型和 everywhereM
(使用 a -> m a
)似乎不支持使用 local
(类型为 m a -> m a
)包装子计算。如果可能的话,我想要一个使用“标准”/“现成”转换的解决方案。
一个有代表性的例子
一种(神秘的)递归数据类型:
{-# LANGUAGE DeriveDataTypeable , Rank2Types , ViewPatterns #-}
import Data.Generics
import Control.Applicative
import Control.Monad.Reader
import Control.Arrow
data Exp = Var Int | Exp :@ Exp | Lam (Binder Exp)
deriving (Eq , Show , Data , Typeable)
newtype Binder a = Binder a
deriving (Eq , Show , Data , Typeable)
Int
带有值的 s
Binder
的数量s 包装它们:
-- Increment all free variables:
-- If G |- e:B then G,A |- weaken e:B.
weaken1 :: Exp -> Exp
weaken1 = w 0
where
w :: Int -> Exp -> Exp
-- Base case: use the environment ('i'):
w i (Var j) = wVar i j
-- Boilerplate recursive case:
w i (e1 :@ e2) = w i e1 :@ w i e2
-- Interesting recursive case: modify the environment:
w i (Lam (Binder e)) = Lam (Binder (w (succ i) e))
wVar :: Int -> Int -> Exp
wVar i j | i <= j = Var (succ j)
| otherwise = Var j
i
weaken1
的参数在
Reader
环境并使用 SYB 自动处理
(:@)
的样板递归案例.
weaken1
, 使用
Reader
环境,但不是 SYB:
weaken2 :: Exp -> Exp
weaken2 e = runReader (w e) 0
where
w :: Exp -> Reader Int Exp
w (Var j) = do
i <- ask
return $ wVar i j
w (e1 :@ e2) = (:@) <$> w e1 <*> w e2
w (Lam (Binder e)) = Lam . Binder <$> local succ (w e)
(:@)
case 是典型的样板递归:everywhereM
自动在这里工作。 Var
case 使用环境,但不修改它:everywhereM
在这里工作,通过申请 mkM
到 Exp -> Reader Int Exp
特定于 Var
案子。 Lam
case 在递归之前修改环境:everywhereM
在这里不起作用(据我所知)。 Binder
type 告诉我们需要在哪里使用 local
, 以便我们希望申请 mkM
到 Binder Exp -> Reader Int (Binder Exp)
具体情况,但我不知道如何。 最佳答案
这是通过创建新的 SYB 遍历 everywhereMM
的解决方案:
newtype MM m x = MM { unMM :: m x -> m x }
mkMM :: (Typeable a , Typeable b) => (m a -> m a) -> m b -> m b
mkMM t = maybe id unMM (gcast (MM t))
-- Apply a 'GenericM' everywhere, transforming the results with a
-- 'GenericMM'.
type GenericMM m = Data a => m a -> m a
everywhereMM :: Monad m => GenericMM m -> GenericM m -> GenericM m
everywhereMM mm m x = mm (m =<< gmapM (everywhereMM mm m) x)
everywhereMM
的定义和
mkMM
是相似的
everywhereM
和
mkM
在
Data.Generics.Schemes
和
Data.Generics.Aliases
;区别在于
everywhereMM
使用
mm
, 一个
GenericMM
, 转换结果。
weaken3
.这个想法是结合标准
GenericM
对于
Var
的情况
Exp
带有新的
GenericMM
适用
local
在
Binder
案子:
type W = Reader Int
weaken3 :: Exp -> Exp
weaken3 e = runReader (w e) 0
where
w :: GenericM W
w = everywhereMM (mkMM b) (mkM v)
b :: W (Binder Exp) -> W (Binder Exp)
b = local succ
v :: Exp -> W Exp
v (Var j) = do
i <- ask
return $ wVar i j
v e = return e
关于generics - 如何在 Scrap Your Boilerplate (SYB) 中使用 `local` 和 `Reader` monad?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16806162/
我是一名优秀的程序员,十分优秀!