gpt4 book ai didi

javascript - Monad的功能组合…不起作用

转载 作者:行者123 更新时间:2023-12-03 07:17:17 25 4
gpt4 key购买 nike

我有一些丑陋的数据,需要进行许多丑陋的null检查。我的目标是编写一个函数集,以使用Maybe monad将空检查保持在最低限度,从而以无点声明式访问/修改它。理想情况下,我可以将Ramda与monad一起使用,但是效果不是很好。

这有效:

const Maybe = require('maybe');
const R = require('ramda');
const curry = fn => (...args) => fn.bind(null, ...args);
const map = curry((fn, monad) => (monad.isNothing()) ? monad : Maybe(fn(monad.value())));
const pipe = (...fns) => acc => fns.reduce((m, f) => map(f)(m), acc);
const getOrElse = curry((opt, monad) => monad.isNothing() ? opt : monad.value());
const Either = (val, d) => val ? val : d;

const fullName = (person, alternative, index) => R.pipe(
map(R.prop('names')),
map(R.nth(Either(index, 0))),
map(R.prop('value')),
map(R.split('/')),
map(R.join('')),
getOrElse(Either(alternative, ''))
)(Maybe(person));

但是,必须键入“map()”十亿次似乎并不很干,也不是很好。我宁愿有一个特殊的pipe / compose函数,将每个函数包装在map()中。

注意我如何使用R.pipe()而不是自定义pipe()?我的自定义实现总是抛出错误, 'isNothing()不是函数,'在执行传递给它的最后一个函数时。

我不确定这里出了什么问题或者是否有更好的方法来做到这一点,但是任何建议都值得赞赏!

最佳答案

首先要做的事情

  • Maybe实现(link)几乎是垃圾-您可能要考虑选择一个不需要实现Functor接口(interface)的实现(就像您对map所做的一样)–我可能会从民俗中建议Data.Maybe。或者,因为您显然不害怕自己执行事情,所以可以自己制作也许^ _ ^


  • 您的map实现不适用于要实现functor接口(interface)的任何functor。即,您的仅适用于Maybe,但是map应该足够通用,以便与任何可映射对象一起工作(如果有这样的话)。

    不用担心,Ramda在框中包含 map –只需将其与实现Maybe方法的.map(例如,Data。也许在上面引用)一起使用


  • 您的curry实现无法正确处理函数。它仅适用于Arity为2的函数-curry应该适用于任何函数长度。
    // given, f
    const f = (a,b,c) => a + b + c

    // what yours does
    curry (f) (1) (2) (3) // => Error: curry(...)(...)(...) is not a function

    // because
    curry (f) (1) (2) // => NaN

    // what it should do
    curry (f) (1) (2) (3) // => 6

    如果您已经在使用Ramda,则实际上没有任何理由自己实现curry,因为它已经包含curry


  • 您的pipe实现将功能组成和映射函子的关注混合在一起(通过使用map)。我建议专门为函数组合保留pipe

    同样,不确定为什么要使用Ramda然后重新发明很多。 Ramda已经包含 pipe

    我注意到的另一件事
    // you're doing
    R.pipe (a,b,c) (Maybe(x))

    // but that's the same as
    R.pipe (Maybe,a,b,c) (x)


  • 您创建的Either可能不是您正在考虑的Either函数或monad。有关更完整的实现,请参见 Data.Either (来自民间故事)


  • 没有观察到一个monad –您的问题是关于monad的函数组合,但是您仅在代码中使用functor接口(interface)。这里有些困惑可能来自Maybe实现FunctorMonad,因此它既可以充当行为(也可以实现其实现的任何其他接口(interface))!在这种情况下,Either也是如此。

    您可能希望看到 Kleisli category 以了解单子(monad)函数的组成,尽管对于这个特定问题它可能与您无关。


  • 功能接口(interface)受法律管辖

    您的问题源于缺乏对函子法则的了解/理解–这意味着如果您的数据类型遵守这些法则,则只能说您的类型是函子。在所有其他情况下,您可能正在处理的是仿函数,但实际上不是。

    functor laws

    where map :: Functor f => (a -> b) -> f a -> f b, id is the identity function a -> a, and f :: b -> c and g :: a -> b

    // identity
    map(id) == id

    // composition
    compose(map(f), map(g)) == map(compose(f, g))


    这对我们说的是,我们可以分别对每个函数编写多个对 map的调用,或者我们可以首先对所有功能进行组合,然后对 map进行一次编写。 –注意在合成法的左侧,我们如何两次调用 .map以应用两个功能,但是在右侧, .map仅被调用一次。每个表达式的结果相同。

    monad laws

    While we're at it, we can cover the monad laws too – again, if your data type obeys these laws, only then can it be called a monad.

    where mreturn :: Monad m => a -> m a, mbind :: Monad m => m a -> (a -> m b) -> m b

    // left identity
    mbind(mreturn(x), f) == f(x)

    // right identity
    mbind(m, mreturn) == m

    // associativity
    mbind(mbind(m, f), g) == mbind(m, x => mbind(f(x), g))


    使用Kleisli合成函数 composek来查看定律可能会更容易一些-现在很明显,Monads确实遵守了关联律

    monad laws defined using Kleisli composition

    where composek :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c)

    // kleisli left identity
    composek(mreturn, f) == f

    // kleisli right identity
    composek(f, mreturn) == f

    // kleisli associativity
    composek(composek(f, g), h) == composek(f, composek(g, h))


    寻找解决方案

    那么,这一切对您意味着什么?简而言之,您要做的工作比必须要做的还要多-特别是要实现所选的Ramda库已经提供的许多功能。现在,这没有任何问题(实际上,如果您审核了许多
    网站上的其他答案),但是如果您误解了某些实现,可能会引起困惑。

    由于您似乎大部分都卡在 map方面,因此我将帮助您看到一个简单的转换。这利用了上面说明的Functor组成定律:

    注意,这使用了 R.pipe,它是从左到右而不是像 R.compose一样从右到左组成的。使用 I prefer right-to-left composition时,可以选择使用 pipecompose –这只是符号上的区别;无论哪种方式,法律都得到遵守。
    // this
    R.pipe(map(f), map(g), map(h), map(i)) (Maybe(x))

    // is the same as
    Maybe(x).map(R.pipe(f,g,h,i))

    我想提供更多帮助,但我不确定100%确实要执行您的功能。
  • Maybe(person)开头
  • 读取person.names属性
  • 获得person.names的第一个索引–是数组还是其他东西?或名字的首字母?
  • 读取.value属性?我们在这里等一个单子(monad)吗? (请查看.chain与我从民俗故事链接的.mapMaybe实现中的Either进行比较)
  • 分割/上的值
  • ''加入值
  • (如果我们有一个值),将其返回,否则返回一些替代的

  • 这是我对发生的事情的最佳猜测,但是我无法在此处显示您的数据,也无法理解您要执行的计算。如果您提供更具体的数据示例和预期的输出,我也许能够帮助您制定更具体的答案。

    备注

    几年前,我也在你的船上。我的意思是仅仅进入函数式编程。我想知道所有小片段如何组合在一起并实际生成人类可读的程序。

    只有将功能性技术应用于整个系统时,才能看到功能性编程所提供的大多数好处。刚开始,您会觉得您不得不引入大量的依赖关系,以“功能方式”重写一个功能。但是,一旦在程序中更多地方发挥了这些依赖性,就可以开始左右降低复杂性。看到的确很酷,但是要花一些时间才能把程序(和头脑)放在那里。

    事后看来,这可能不是一个很好的答案,但是我希望这对您有所帮助。对我来说,这是一个非常有趣的话题,很高兴为您解答其他任何问题^ _ ^

    关于javascript - Monad的功能组合…不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44515578/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com