这是一个有效的monad转换器在Javascript中? [英] Is this a valid monad transformer in Javascript?

查看:91
本文介绍了这是一个有效的monad转换器在Javascript中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了更好地理解单变压器我实现了一个。由于Javascript是动态类型化的,因​​此我不会模仿类型或数据构造函数,而是只声明普通的旧Javascript对象,它们保存相应的静态函数以形成特定的monad / transform。其基本思想是将这些方法应用于容器类型的值/值。类型和容器是分开的。

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]]预计
arraym.chain(y => addm(x)(y))(arrayOfMaybes))([[10]])
$ p

这个问题的原因是


  • 这不是一个有效的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.

Arrays can contain any number of elements. It is trivial to extend Arrays so that they implement the monad interface. Arrays 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 Arrays 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 arrays of maybes.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆