我试图熟悉JavaScript中的函数式编程。我只是read指针函数是:
具有
of
函数的对象,可将任何单个值放入其中。ES2015添加
Array.of
使数组成为一个有针对性的算符。
我的问题是究竟是什么意思"单一价值"?
我想制作一个Functor / Container(就像在https://drboolean.gitbooks.io/mostly-adequate-guide/content/ch8.html中),它将给定尺寸(宽度,高度)的网格保存为一维数组,并允许我对其进行转换。作为一个普通的对象,我会把它存储为{ width: 2, height: 2, list: [1, 2, 3, 4] }
,但我想把它放在一个仿函数中,我不知道该怎么做。
我知道使用像这样的尖头仿函数存储单个值是完全没问题的:
Container.of(47)
但是可以使用object作为值,假设对象是"单个值":
Grid.of({ width: 2, height: 2, list: [1, 2, 3, 4] })
或者甚至喜欢这样:
Grid.of(2, 2, [1, 2, 3, 4])
答案 0 :(得分:7)
遗憾的是,https://github.com/hemanth/functional-programming-jargon中的解释并不十分准确。
指向仿函数实际上是一个仿函数F
以及为每种类型 of
定义的函数a
,并且发送类型为x
的{{1}}值a
为of(x)
类型的值F a
。在Hindley-Milner signature中,它看起来像这样:
of :: a -> F a
例如,数组仿函数指向of = x => [x]
,为任何类型x
的每个值a
定义。
此外,函数of
(或更准确地说,函数of
的集合,因为每种类型a
都有一个函数)必须是从身份函子到{的自然转换{1}}。这意味着F
应用于函数的值等于of
应用于函数的参数,然后映射到函数上:
of
例如,在Array示例中,您有
of(f(x)) === of(x).map(f)
所以[f(x)] === [x].map(f),
确实是一种自然的转变。
但您也可以将x => [x]
重新定义为
of
,即使of = x => [x, x]
[f(x), f(x)] === [x, x].map(f)
方法保持不变,也会将Array
转换为另一个尖头仿函数。 (请注意,在每种情况下,您只能获得非常特殊的数组作为map
的值。)
但是,您无法将of(x)
定义为例如
of
现在
of = x => [x, 0]
[f(x), 0] !== [x, 0].map(f)
完全没问题,并将包裹的对象返回到var grid = Grid.of({ width: 2, height: 2, list: [1, 2, 3, 4] })
。然后,您可以将Grid
与常规函数grid
从普通对象映射到普通对象,结果与应用f
并包装到f
相同,因为自然转化法。请注意,通过这种方式,您还可以使用Grid
甚至Grid.of
之类的任何其他值来调用Grid.of({width: 2})
。或者,您可以限制定义Grid.of(2)
的类型,然后该值必须只是您允许的类型。
这个有点棘手:
Grid.of
这会将Grid.of(2, 2, [1, 2, 3, 4])
应用于多个参数。由于Grid.of
根据定义只是一个参数的函数,因此结果将是Grid.of
,这可能不是您想要的。如果你真的想要提供所有值,你可能想写
Grid.of(2)
或者,您可以通过在内部将它们预先包装到数组中然后应用Grid.of([2, 2, [1, 2, 3, 4]])
来将Grid.of
扩展为多个参数。这实际上取决于你所追求的目标。
有关实际使用示例,请参阅例如here其中一个"无聊"任务是通过Grid.of
从普通值定义的。另一方面,here是一个更有趣的任务包装一个你不会用Task.of
得到的函数。但重要的是,两个任务都可以使用与两个示例中所示相同的统一接口。
另请注意,这些示例中没有使用任何应用仿函数,因此仍然使用尖头仿函数而不是应用。
溶液。
另请参阅https://github.com/MostlyAdequate/mostly-adequate-guide-it/blob/master/ch9.md#pointy-functor-factory以获得Pointed Functor的精彩介绍和实际使用。
答案 1 :(得分:3)
但是假设object是“单值”,可以使用object作为值:
是。 of
应该使用任何值并将其放入容器中。一个对象肯定是这样一个单一的值。
Grid.of(2, 2, [1, 2, 3, 4])
没有。 of
应该采用一个参数。如果你想在一个仿函数中放入多个值,先将它们放在另一个结构中,然后将该结构放在仿函数中,或者通过其函数(of
)以外的其他结构构造仿函数。
Grid.of({ width: 2, height: 2, list: [1, 2, 3, 4] })
不,如果您希望返回输入,那么它将无效。 of
应该按原样输入输入并围绕它包装结构。对于你的网格,它肯定会是这样的:
// Grid<A>
class Grid {
// Int -> Int -> [A] -> Grid<A>
constructor(w, h, vals) {
assert(Number.isInteger(w) && Number.isInteger(h));
this.width = w;
this.height = h;
const list = Array.from(vals);
assert(list.length == w * h);
this.list = list;
}
// Grid<A> -> (A -> B) -> Grid<B>
map(f) {
return new Grid(this.width, this.height, this.list.map(f));
}
// A -> Grid<A>
static of(x) {
return new Grid(1, 1, [x]);
}
}
因此,上述调用将创建Grid
个对象,而不是四个数字的网格。请注意,of
不是构造仿函数实例的唯一方法,它只是从单个元素构造实例的方法。
请注意of
作为Applicative的一部分是最重要的,对普通的Functors来说并不那么有趣。顺便说一下,如果你对函数式编程概念感兴趣,你也应该能够使Grid
成为Monoid,Traversable和Monad - 见https://github.com/fantasyland/fantasy-land。