我想了解buzzdecafe's Chain chain chain article
那篇文章解释了如何使用R.chain将数组中的第一个值附加到该数组的(结尾),以及为什么会这样。
const f = chain(append, head); //=> f :: [x] -> [x]`
f([1, 2, 3]); //=> [1, 2, 3, 1]
在最后一段中,他写了
头部是m a
作为刚刚开始尝试函数式编程的人,我不能理解。
我不完全理解文章中从不同类型的链中从数组到函数的替换,反之亦然。
R.chain的类型是:
(a -> m b) -> m a -> m b
我知道链可以是一个函数。因此具有类型x → [x] → [x]
的R.append可以重写为a -> m b
并且适合R.chain类型的第一部分。我认为这意味着我们现在已定义(或任何单词)m b
为[x] -> [x]
,以便最后m b
必须替换为[x] -> [x]
?
在这种情况下,我们看起来像这样:
(a -> [x] -> [x]) -> m a -> ([x] -> [x])
由于a和x的类型相同(在本例中为数字),我们有:
(x -> [x] -> [x]) -> m x -> ([x] -> [x])
所以第一个过去匹配R.append。结尾匹配返回函数的类型。太好了,我觉得我有点理解......
但是...... m x
之间如何适应R.head? m x
可以是一个返回x类型的函数吗?好?但那个功能的输入怎么样?我怎样才能看到并理解[x]
是一个与R.chain类型兼容的有效输入以及我们所做的公式操作的其余部分?
答案 0 :(得分:1)
从这里开始:
链::(a - >(x - > b)) - > (x - > a) - > (x - > b)
看起来你已经理解了,我们在这里解释m b
是"一个带x
并返回b
&#34的函数;。因此,m a
将是"一个带x
并返回a
"的函数。
将此并排与concat
的签名进行比较(我将使用y
以避免在不同的x
es之间产生混淆:
(a -> (x -> b))
y -> [y]-> [y]
我们可以看到a
为y
,x
为[y]
,b
也为[y]
。因此,使用x
并返回a
的函数将具有签名[y] -> y
,这正是head
具有的签名。
所以我们最终得到的是:
append head
a -> m b m a m b
a -> x -> b -> ( x -> a) -> ( x -> b )
(y -> [y] -> [y]) -> ([y] -> y) -> ([y] -> [y])
这有助于清除它吗?
另一种看待这种情况的方法是,如果f
和g
都是函数,那么:
chain(f, g)(x) is equivalent to f(g(x), x)
这正是我们在Ramda source中看到的:
fn(monad(x))(x)
从这一点开始,我们可以看到函数f
和g
是chain
- 当以下两者都为真时,它们就可以了:
g(x)
与f
f
的第二个参数与g
的第一个参数