如何正确使用尖函数
How to use pointed functor properly
我正在尝试熟悉 JavaScript 中的函数式编程。我刚刚 read 那个指针仿函数是:
An object with an of
function that puts any single value into it.
ES2015 adds Array.of
making arrays a pointed functor.
我的问题是 "single value" 到底是什么意思?
我想制作一个 Functor/Container(如 https://drboolean.gitbooks.io/mostly-adequate-guide/content/ch8.html),将给定维度(宽度、高度)的网格保存为一维数组,并允许我对其进行转换。作为一个普通对象,我会把它存储为 { width: 2, height: 2, list: [1, 2, 3, 4] }
但我想把它放在一个仿函数中,但我不确定如何正确地做。
我知道像这样使用尖函数来存储单个值是非常好的:
Container.of(47)
但是假设对象是 "single value":
可以使用对象作为值吗
Grid.of({ width: 2, height: 2, list: [1, 2, 3, 4] })
甚至像这样:
Grid.of(2, 2, [1, 2, 3, 4])
But is it ok to use object as value assuming object is a "single value":
是的。 of
应该取 any 值并将其放入容器中。一个对象肯定就是这样一个单一的值。
Grid.of(2, 2, [1, 2, 3, 4])
没有。 of
应该采用单个参数。如果你想把多个值放在一个函子里,先把它们放在另一个结构里,然后把那个结构放在函子里,或者用它的点函数以外的东西构造函子 (of
).
Grid.of({ width: 2, height: 2, list: [1, 2, 3, 4] })
不,如果您希望 return 输入那么它将不起作用。 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.
不幸的是https://github.com/hemanth/functional-programming-jargon中的解释不是很准确。
一个 pointed functor 实际上是一个 functor F
以及为 每种类型 定义的函数 of
a
,并将 a
类型的值 x
发送到 F a
类型的值 of(x)
。在 Hindley-Milner signature 中它看起来像这样:
of :: a -> F a
例如,数组仿函数指向 of = x => [x]
,为任何类型 a
的每个值 x
定义。
此外,函数 of
(或者更准确地说,函数的集合 of
因为每种类型都有一个 a
)必须是恒等函子的自然转换进入 F
。这意味着 of
应用于函数的值等于 of
应用于函数的参数然后映射到函数:
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] })
完全没问题,returns 您的对象通过包装进入 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
扩展到多个参数,方法是 pre-wrapping 它们在内部数组中,然后应用 Grid.of
。这真的取决于你追求什么。
有关真实世界的用法示例,请参见例如here where a "boring" Task is defined via Task.of
from a plain value. On the other hand here 是一个更有趣的任务,它包装了一个 Task.of
无法获得的函数。但重要的是,两个任务都可以与两个示例中所示的相同统一界面一起使用。
另请注意,这些示例中没有使用应用函子,因此仍然使用了指向函子而不是应用函子。
已添加。
另请参阅 https://github.com/MostlyAdequate/mostly-adequate-guide-it/blob/master/ch9.md#pointy-functor-factory,了解 Pointed Functor 的精彩介绍和实际应用。
我正在尝试熟悉 JavaScript 中的函数式编程。我刚刚 read 那个指针仿函数是:
An object with an
of
function that puts any single value into it.ES2015 adds
Array.of
making arrays a pointed functor.
我的问题是 "single value" 到底是什么意思?
我想制作一个 Functor/Container(如 https://drboolean.gitbooks.io/mostly-adequate-guide/content/ch8.html),将给定维度(宽度、高度)的网格保存为一维数组,并允许我对其进行转换。作为一个普通对象,我会把它存储为 { width: 2, height: 2, list: [1, 2, 3, 4] }
但我想把它放在一个仿函数中,但我不确定如何正确地做。
我知道像这样使用尖函数来存储单个值是非常好的:
Container.of(47)
但是假设对象是 "single value":
可以使用对象作为值吗Grid.of({ width: 2, height: 2, list: [1, 2, 3, 4] })
甚至像这样:
Grid.of(2, 2, [1, 2, 3, 4])
But is it ok to use object as value assuming object is a "single value":
是的。 of
应该取 any 值并将其放入容器中。一个对象肯定就是这样一个单一的值。
Grid.of(2, 2, [1, 2, 3, 4])
没有。 of
应该采用单个参数。如果你想把多个值放在一个函子里,先把它们放在另一个结构里,然后把那个结构放在函子里,或者用它的点函数以外的东西构造函子 (of
).
Grid.of({ width: 2, height: 2, list: [1, 2, 3, 4] })
不,如果您希望 return 输入那么它将不起作用。 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.
不幸的是https://github.com/hemanth/functional-programming-jargon中的解释不是很准确。
一个 pointed functor 实际上是一个 functor F
以及为 每种类型 定义的函数 of
a
,并将 a
类型的值 x
发送到 F a
类型的值 of(x)
。在 Hindley-Milner signature 中它看起来像这样:
of :: a -> F a
例如,数组仿函数指向 of = x => [x]
,为任何类型 a
的每个值 x
定义。
此外,函数 of
(或者更准确地说,函数的集合 of
因为每种类型都有一个 a
)必须是恒等函子的自然转换进入 F
。这意味着 of
应用于函数的值等于 of
应用于函数的参数然后映射到函数:
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] })
完全没问题,returns 您的对象通过包装进入 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
扩展到多个参数,方法是 pre-wrapping 它们在内部数组中,然后应用 Grid.of
。这真的取决于你追求什么。
有关真实世界的用法示例,请参见例如here where a "boring" Task is defined via Task.of
from a plain value. On the other hand here 是一个更有趣的任务,它包装了一个 Task.of
无法获得的函数。但重要的是,两个任务都可以与两个示例中所示的相同统一界面一起使用。
另请注意,这些示例中没有使用应用函子,因此仍然使用了指向函子而不是应用函子。
已添加。
另请参阅 https://github.com/MostlyAdequate/mostly-adequate-guide-it/blob/master/ch9.md#pointy-functor-factory,了解 Pointed Functor 的精彩介绍和实际应用。