这是一个有效的monad转换器在Javascript中? [英] Is this a valid monad transformer in Javascript?
问题描述
Array
s可以包含任意数量的元素。扩展 Array
s以使它们实现monad接口是微不足道的。 Array
s也可以表示也许
类型的两种变体。一个空的 Array
对应于 nothing
。具有单个元素的数组
对应于
(a)
。因此,我将使用 Array
s作为我的容器类型。请注意,这是一个快速而肮脏的实现,仅供学习:
const array = {
of:x = > Array.of(x),
map:f => ftor => ftor.map(f),
ap:ftor => gtor => array.flatten(array.map(f => array.map(f)(gtor))(ftor)),
flatten:ftor => ftor.reduce((xs,y)=> xs.concat(y),[]),
chain:mf => ftor => array.flatten(array.map(mf)(ftor))
}
const maybe = {
of:array.of,
empty:()= > [],
throw:ftor => {if(ftor.length> 1)throw Error(indeterministic value);返回ftor},
map:f => ftor => maybe.throw(ftor).map(f),
ap:ftor => gtor => maybe.flatten(maybe.map(f => maybe.map(f)(gtor))(ftor)),
flatten:array.flatten,
chain:mf => ftor => maybe.flatten(maybe.map(mf)(ftor)),
T:M => {
return {
of:x => M.of(maybe.of(x)),
empty:()=> M.of(maybe.empty()),
map:f => ftor => M.map(gtor => maybe.map(f)(gtor))(ftor),
ap:ftor => gtor => M.flatten(M.map(htor => M.map(itor => maybe.ap(htor)(itor))(gtor))(ftor)),
flatten:maybe.flatten,
链:mf => ftor => M.chain(gtor => maybe.chain(mf)(gtor))(ftor)
};
}
};
现在我将一个可能的转换器与monadic数组结合起来,以获得一个monad,它可以处理
可能
s。
const arraym = maybe.T(array);
const add = x => y => x + y;
const addm = x => y => [x + y];
const arrayOfMaybes = [[1],[],[3]]
将 arraym
作为应用函子,一切都按预期工作:
/ / arrays:[[11],[],[13]]如预期的那样
arraym.ap(arraym.map(add)(arrayOfMaybes))(arraym.of(10));
然而,当我应用 chain 时,错误:
//产量:[11,13]但[[11],[13]]预计
$ p
arraym.chain(y => addm(x)(y))(arrayOfMaybes))([[10]])
这个问题的原因是
- 这不是一个有效的monad变压器?
- 我应用链的方式是错误的吗?
- 我对结果的期望是错误的吗?
这个问题的原因是我应用链的方式是错误的吗?
是的。你需要传递一个 mf
,它返回一个 arraym
,而不是数组<$ code>就像
addm
一样。您可以使用
const addmm = x => y => array.map(maybe.of)(addm(x)(y))
arraym.chain(x => arraym.chain(addmm(x))(arrayOfMaybes))([[10]])
为了解决这个问题,你也可以考虑实现 lift
为每个monad变压器。
In order to better understand monad transformers I implemented one. Since Javascript is dynamically typed I don't mimic type or data constructors but declare only plain old Javascript objects, which hold the corresponding static functions to form a specific monad / transformer. The underlying idea is to apply these methods to a value/values in a container type. Types and containers are separated so to speak.
Array
s can contain any number of elements. It is trivial to extend Array
s so that they implement the monad interface. Array
s can also represent the two variants of the maybe
type. An empty Array
corresponds to nothing
. An Array
with a single element corresponds to just(a)
. Consequently I will use Array
s as my container type. Please note that this is an quick and dirty implementation just for learning:
const array = {
of: x => Array.of(x),
map: f => ftor => ftor.map(f),
ap: ftor => gtor => array.flatten(array.map(f => array.map(f) (gtor)) (ftor)),
flatten: ftor => ftor.reduce((xs, y) => xs.concat(y), []),
chain: mf => ftor => array.flatten(array.map(mf) (ftor))
}
const maybe = {
of: array.of,
empty: () => [],
throw: ftor => { if (ftor.length > 1) throw Error("indeterministic value"); return ftor },
map: f => ftor => maybe.throw(ftor).map(f),
ap: ftor => gtor => maybe.flatten(maybe.map(f => maybe.map(f) (gtor)) (ftor)),
flatten: array.flatten,
chain: mf => ftor => maybe.flatten(maybe.map(mf) (ftor)),
T: M => {
return {
of: x => M.of(maybe.of(x)),
empty: () => M.of(maybe.empty()),
map: f => ftor => M.map(gtor => maybe.map(f) (gtor)) (ftor),
ap: ftor => gtor => M.flatten(M.map(htor => M.map(itor => maybe.ap(htor) (itor)) (gtor)) (ftor)),
flatten: maybe.flatten,
chain: mf => ftor => M.chain(gtor => maybe.chain(mf) (gtor)) (ftor)
};
}
};
Now I combine a maybe transformer with the monadic array to get a monad that can handle array
s of maybe
s.
const arraym = maybe.T(array);
const add = x => y => x + y;
const addm = x => y => [x + y];
const arrayOfMaybes = [[1],[],[3]]
When I treat arraym
as an applicative functor, everything works as expected:
// yields: [[11],[],[13]] as expected
arraym.ap(arraym.map(add) (arrayOfMaybes)) (arraym.of(10));
However, when I apply chain
something goes wrong:
// yields: [11,13] but [[11],[13]] expected
arraym.chain(x => arraym.chain(y => addm(x) (y)) (arrayOfMaybes)) ([[10]])
Is the cause of this problem
- that this isn't a valid monad transformer?
- that the way I apply chain is wrong?
- that my expectation regarding the result is wrong?
Is the cause of this problem that the way I apply chain is wrong?
Yes. You need to pass an mf
that returns an arraym
, not an array
like addm
does. You could use
const addmm = x => y => array.map(maybe.of)(addm(x)(y))
arraym.chain(x => arraym.chain( addmm(x) )(arrayOfMaybes))([[10]])
To help with this, you also might consider implementing lift
for every monad transformer.
这篇关于这是一个有效的monad转换器在Javascript中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!