微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

javascript – 为什么我可以将函数传递给提升的R.divide?

鉴于以下内容
var average = R.lift(R.divide)(R.sum,R.length)

为什么这可以作为平均点的免费实现?我不明白为什么我可以在它们是函数时传递R.sum和R.length,因此,我不能将提升的R.divide映射到函数R.sum和R.length上,这与以下示例不同:

var sum3 = R.curry(function(a,b,c) {return a + b + c;});
R.lift(sum3)(xs)(ys)(zs)

在上述情况下,xs,ys和zs中的值在非确定性上下文中求和,在这种情况下,将提升函数应用于给定计算上下文中的值.

进一步说明,我理解应用提升函数就像连续使用R.ap到每个参数.两行都评估相同的输出

R.ap(R.ap(R.ap([tern],[1,2,3]),[2,4,6]),[3,6,8])
R.lift(tern)([1,3],6],8])

检查文档说:

“lifts” a function of arity > 1 so that it may “map over” a list,Function or other object that satisfies the FantasyLand Apply spec.

至少对我来说,这似乎不是一个非常有用的描述.我正试图建立一个关于电梯使用的直觉.我希望有人可以提供.

解决方法

一个很酷的事情是a – > b可以支持 map.是的,功能是仿函数

让我们考虑一下地图的类型:

map :: Functor f => (b -> c) -> f b -> f c

让我们替换Functor f => f with Array给我们一个具体的类型:

map :: (b -> c) -> Array b -> Array c

让我们替换Functor f =>这个时候可能还有:

map :: (b -> c) -> Maybe b -> Maybe c

相关性很明显.让我们替换Functor f => f使用a,a来测试二进制类型:

map :: (b -> c) -> Either a b -> Either a c

我们经常将a到b的函数类型表示为 – > b,但这真的只是功能a b的糖.让我们使用长格式并将上面的签名中的Either替换为Function:

map :: (b -> c) -> Function a b -> Function a c

因此,映射函数给我们一个函数,它将应用b – > c函数为原始函数的返回值.我们可以使用a – >重写签名. b糖:

map :: (b -> c) -> (a -> b) -> (a -> c)

注意什么? compose的类型是什么?

compose :: (b -> c) -> (a -> b) -> a -> c

所以compose只是专门用于Function类型的map!

第二个很酷的事情是a – > b可以支持ap.函数也是应用函子!这些被称为Fantasy Land规范中的Apply.

让我们考虑一下ap的类型:

ap :: Apply f => f (b -> c) -> f b -> f c

让我们替换Apply f => f与数组:

ap :: Array (b -> c) -> Array b -> Array c

现在,使用Either a:

ap :: Either a (b -> c) -> Either a b -> Either a c

现在,使用功能a:

ap :: Function a (b -> c) -> Function a b -> Function a c

什么是函数a(b – > c)?这有点令人困惑,因为我们混合了两种样式,但它是一个函数,它接受一个类型a的值并返回一个从b到c的函数.让我们用a – >重写b风格:

ap :: (a -> b -> c) -> (a -> b) -> (a -> c)

任何支持map和ap的类型都可以“解除”.我们来看看lift2

lift2 :: Apply f => (b -> c -> d) -> f b -> f c -> f d

请记住,函数a满足Apply的要求,因此我们可以替换Apply f => f与函数a:

lift2 :: (b -> c -> d) -> Function a b -> Function a c -> Function a d

哪个更清楚:

lift2 :: (b -> c -> d) -> (a -> b) -> (a -> c) -> (a -> d)

让我们重新审视您的初始表达:

//    average :: Number -> Number
const average = lift2(divide,sum,length);

平均值([6,7,8])有什么作用? a([6,8])给予a – > b函数(sum),产生b(21). a也给a – > c函数(长度),产生c(3).现在我们有了b和c,我们可以将它们提供给b – > c – > d函数(除)产生d(7),这是最终结果.

因此,因为Function类型可以支持map和ap,所以我们可以免费收敛(通过lift,lift2lift3).我实际上想从Ramda中移除converge,因为它没有必要.

请注意,我有意避免在此答案中使用R.lift.由于决定支持任何arity的功能,它具有无意义的类型签名和复杂的实现.另一方面,Sanctuary特定的提升功能具有清晰的类型签名和简单的实现.

原文地址:https://www.jb51.cc/js/159139.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐