换能器与部分应用的功能有何不同?

时间:2014-10-30 13:07:39

标签: haskell clojure transducer

在阅读了关于Clojure(http://blog.podsnap.com/ducers2.html)介绍传感器的这篇文章后,我对传感器的含义感到困惑。是否在Haskell中部分应用map,例如map (+1)传感器?起初我认为这是使用部分应用程序的Clojure方式,但随后本文继续在Haskell中使用显式类型实现它。它在Haskell中有什么用处?

1 个答案:

答案 0 :(得分:41)

在Clojure中,(map inc)是一个传感器,但不在Haskell中,因为Haskell必须服从currying,但是一个无类型的Lisp可以打破默认的curry惯例。换能器的类型是:

type Transducer a b = forall r . (b -> r -> r) -> (a -> r -> r)

我们说换能器'将a变成b'。是的,ab似乎是“向后”的右侧。 forall表示传感器必须将r作为常规类型变量,但完全允许专注于ab

让我在foldr中反转两个参数:

-- cf. with foldr :: (x -> r -> r) -> r -> [x] -> r
ffoldr :: (x -> r -> r) -> [x] -> r -> r
ffoldr = flip . foldr

(我们也可以使用foldl,但以后会倾向于反转)。这意味着可以使用Transducerffoldr的第一个参数从x转换为y,这样我们就可以使用[x]来处理y -> r -> r foldr使用([x], r)。传感器位于输入(y, r) -> r和最终处理器ffoldr :: Transducer [x] x之间。

我翻开了后两个论点,也强调了(.) :: Transducer a b -> Transducer b c -> Transducer a c 。通过使用参数的对称性,我们还有一个通用的传感器组合,恰好只是函数组合:

forall r

(如果您认为提供这些.条款让我们反转您通常使用tfilter :: (a -> Bool) -> (a -> r -> r) -> a -> r -> r -- or: (a -> Bool) -> Transducer a a tfilter predicate f a = if predicate a then f a else id 的方式很酷,您可以通过一种名为“延续传递”的技术随意执行。)

例如,这里是滤波器传感器:

f

仅当谓词成立时,这会将缩减函数a应用于rtmap :: (a -> b) -> (b -> r -> r) -> a -> r -> r tmap ba f a = f (ba a) 。还有一个映射传感器:

foldr

这为任何“transducable”类型提供了可组合的map / filter语义:一个map / filter fn可以用于多个上下文。

传感器类型具有可爱的同构性:事实证明,列表forall r. (x -> r -> r) -> r -> r的{​​{1}}完全等同于列表[x](它是“教会编码”) list),因此将参数a交换到传感器定义的最前面使我们(IMO更容易理解!)类型type TransL a b = a -> [b]。这更容易理解:

tl_map f = \a -> [f a]
tl_filter predicate = \a -> if predicate a then [a] else []

要在列表中运行这些,请使用concatMap ...恰好是>>=!所以你只需要写collection >>= transducer并获得转换后的集合。 TransL a b的含义是,“取a原始列表的每个元素,并给我0个或更多类型b的元素拼接到我的传出列表中。”当谓词不起作用时,它通过拼接0个元素进行过滤;它通过为每个输入元素产生1个输出元素进行映射;另一个操作tl_dupe = \a -> [a, a]是一个传感器,它复制列表中的元素,[1,2,3] >>= tl_dupe变为[1,1,2,2,3,3]

foldr似乎是Transducer [x] x,现在看来它与id :: TransL [x] x完全相同,后者可以在中间执行concat操作计算;这个代数中的身份函数实际上是return = \a -> [a],也写成(:[])唯一损失是我们无法再使用.来构建这些内容,但实际上Control.Monad中提供的内容与Kleisli合成运算符>=>相同

如此长的故事简短,换能器是函数a -> [b]巧妙地转换为一些教会编码,以便列表monad的这些Kleisli箭头的Kleisli合成运算符变为简单(.)