我正在修改提供Category
和Arrow
实例的Control.Foldl数据类型。
我的定义如下:
data FoldlCat a b = forall x c. FoldlCat (x -> a -> c) x (c -> x) (c -> b)
其中第一个参数代表“步”功能(savedState -> newInput -> intermediateValue
),第二个代表初始savedState
,第三个代表“保存”功能(intermediateValue -> savedState
),最后一个是一个“提取”功能(intermediateValue -> newOutput
)。
map (*10) . scanl (+) 0
之类的内容可以表示为FoldlCat (+) 0 id (*10)
。
保存功能的主要目的是促进id
和arr
的定义,如下所示:
id = FoldlCat (\_ x -> x) () (const ()) id
现在我试图想出一个ArrowLoop
的实例是不成功的。我看不出有任何理由不可能,但是,我对fix
这样的概念感到不舒服。到目前为止,我最好的尝试是typechecks,但永远循环。
instance ArrowLoop FoldlCat where
loop (FoldlCat s b a d) = FoldlCat step b (a . snd) fst where
step x = loop' d (s x)
loop' f g x = let ~(v, ~(c,d)) = let ~v = g (x,d) in (v, f v)
in (c, v)
如果有人可以分享他们定义这样一个实例的方法(如果它可以在(.)
内的累加器中使用严格的元组),或者解释为什么这是不可能的,或者解释为什么,我将不胜感激。 FoldlCat更好的结构。
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE Arrows #-}
import Data.List (unfoldr)
import Prelude hiding (id, (.))
import Control.Category
import Control.Arrow
-- | FoldlCat step init save export
data FoldlCat a b = forall x c. FoldlCat (x -> a -> c) x (c -> x) (c -> b)
mapCat :: (a -> b) -> FoldlCat a b
mapCat f = FoldlCat (\_ x -> x) () (const ()) f
evalList :: FoldlCat t b -> [t] -> [b]
evalList (FoldlCat s b a d) ys = unfoldr stepan (b, ys) where
stepan (accVal, (x:xs)) = Just (nexVal, (newAcc, xs)) where
newMeta = s accVal x
newAcc = a newMeta
nexVal = d newMeta
stepan (accVal, []) = Nothing
delay :: b -> FoldlCat b b
delay def = FoldlCat (,) def snd fst
instance Category FoldlCat where
id = mapCat id
(.) (FoldlCat step2 begin2 acc2 done2) (FoldlCat step1 begin1 acc1 done1) =
let step = \(a, b) y -> let !a' = step1 a y
!b' = step2 b (done1 a') in (a', b')
begin = (begin1, begin2)
acc = \(x, y) -> ((acc1 x), (acc2 y))
done = \(a, b) -> done2 b
in
FoldlCat step begin acc done
instance Arrow FoldlCat where
arr f = mapCat f
first (FoldlCat s b a d) = FoldlCat step b (a . fst) extF where
step = (\a (x, y) -> (s a x, y))
extF = (\(ok, y) -> (d ok, y))
instance ArrowLoop FoldlCat where
loop (FoldlCat s b a d) = FoldlCat step b (a . snd) fst where
step x = loop' d (s x)
loop' f g x = let ~(v, ~(c,d)) = let ~v = g (x,d) in (v, f v)
in (c, v)
chaseFromZero = proc target -> do
rec let step = signum (target - x)
x <- FoldlCat (+) 0 id id <<< delay 0 -< step
id -< x
main = print $ evalList chaseFromZero [1..5]
编辑虽然我不确定它的工作原理和原因,但在step
中修复(.)
的严格性(即删除let !a' = step1 a y
中的爆炸)似乎会使这个例子工作。