我已经在一个算法中工作了一段时间,该算法需要组合它的函数部分,以便组合的返回值包含两个函数的输出。例如(在JavaScript中):
const double = x => x * 2
const increment = x => x + 1
const doubleThenIncrement = composeConservingOutputs(increment, double)
doubleThenIncrement(2) -- => [4, 5]
字符串
我一直在想这是不是已知的合成模式在Haskell中,这似乎可以通过一种干净的方式实现,将一个箭头的输出管道连接到另一个箭头的扇出和id:
import Control.Arrow
double = (*) 2
increment = (+) 1
doubleThenIncrement = arr double >>> (arr id &&& arr increment)
型
但我找不到这是不是一个常见的/已知的模式。
我发现这很有用,因为它允许非常容易地检查中间函数的输出以进行调试,这让我觉得这可能已经是一件事了。
一个Hoogle search for the pattern (a -> b) -> (b -> c) -> (a -> (b, c))证明是徒劳的。
谢啦,谢啦
2条答案
按热度按时间wooyq4lh1#
在不需要额外导入的情况下,您可以使用
字符串
此函数首先将其参数加倍,然后使用函数的
Monad
示例将double
的返回值用作(,)
函数的 both 参数,然后将increment
应用于结果元组中的 second 元素。通过一个导入,您可以稍微简化中间部分:
型
(For函数,
join
的实现实际上是join f = \x -> f x x
。我们使用double
的结果调用(,)
作为两个参数。join (,) . double
是\x -> (,) (double x) (double x)
是(double x, double x)
。)您可以定义一个函数,以
increment
和double
作为参数来返回doubleThenIncrement
:型
在所有可怕的免分荣耀中,它将是
型
(Or,你可以只写
型
但那有什么乐趣呢)
2izufjch2#
在Haskell中为您想要的内容提出通用解决方案是很棘手的,因为中间值需要具有相同的类型。
注销中间值的模式是
Writer
monad所适合的。这里的限制是“写入”值必须实现Monoid
类型类。我怀疑这在你的情况下是可以的,如果你只是用它来调试的话。您可以将值转换为String
,即Monoid
。我会定义一个函数
writeParam f x = (show x, f x)
(如果你喜欢箭头),你可以把所有的函数都 Package 进去。返回元组Monoid a => ((,) a)
的函数实际上是writer monad的一个简单实现,所以你可以用常规的monad组合来组合这些函数,如下所示:字符串
顺便说一下,如果你喜欢箭头,你也可以将
writeParam
定义为writeParam = (show &&&)
,如果你想更通用的话,甚至可以只定义为writeParam = (id &&&)
。虽然IMO对此不太清楚。