首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >和应用函数需要一个函数作为值。

和应用函数需要一个函数作为值。
EN

Stack Overflow用户
提问于 2018-07-26 05:50:25
回答 1查看 112关注 0票数 3

我实际上正在学习函数式编程,我正在努力学习和使用金银花

现在,我正在尝试实现https://fsharpforfunandprofit.com/monadster/中描述的"monadster“程序。

这是我现在所拥有的(仅仅是开始)

代码语言:javascript
复制
const State = require("crocks/State");

const LivingPart = (unitOfForce, deadThing) => ({ unitOfForce, deadThing });

// Creating the potential living thing
const makeLiveThingM = deadThing => {
  const becomeAlive = vitalForce => {
    const unitOfForce = 1;
    const remaining = vitalForce - unitOfForce;

    return { part: LivingPart(unitOfForce, deadThing), remaining };
  };

  return State.get(becomeAlive);
};

// Using containers
const deadLegM = makeLiveThingM("deadLeg");
const deadArmM = makeLiveThingM("deadArm");

const livingThings = deadLegM.ap(deadArmM).evalWith(1);

console.log(livingThings);

我的问题是,它引发了以下错误:

代码语言:javascript
复制
/Users/pc/Soft/experiments/functional/crocks/node_modules/crocks/State/index.js:101
        throw new TypeError('State.ap: Source value must be a function')
        ^

TypeError: State.ap: Source value must be a function

据我所见,这可能是因为我不了解apply函数,也不了解State.get的运行方式。对我来说,它在代码中接受一个函数作为它的内部值,但看起来并非如此。

有人能解释并告诉我我在这里做错了什么吗?

谢谢你的帮忙

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-07-27 04:41:27

欢迎使用JS进行函数式编程,并感谢您给crocks一次机会。

在看这篇文章时,需要注意的一点是,作者介绍的是State ADT内部的机制是如何工作的,而不是实际上如何使用现有的State ADT。

我将解释如何手动处理State事务,这与您在实现中的功能非常接近。然后,我将给出一个简短的示例,说明如何使用构造助手(比如getmodify来减少VitalForce)来处理和构建State事务。

此外,我还将简要解释如何使用Applicatives。

因此,首先,让我们从crocks引入几个ADT

代码语言:javascript
复制
const Pair = require('crocks/Pair')
const State = require('crocks/State')

我们需要状态构造函数来接受一个函数,它将返回一个Pair (作者在文章中提到的元组)。构造函数的工作原理可以找到这里

在讨论状态函数之前,我们需要这个LivingPart函数:

代码语言:javascript
复制
// LivingPart :: (Integer, String) -> Object
const LivingPart = (unitOfForce, part) =>
  ({ [part]: { unitOfForce } })

我已经改变了原来的结构,这样我们就可以将任何给定的Part合并到另一个。

有了这一点,我们就可以实现makeLiveThing了。在你的实施过程中你已经有了很多。这里唯一真正的区别是我们需要用函数构造State ADT并返回Pair。注意,我们仍然引入了String,但是返回一个runWith调用时将执行的runWith ADT。请记住,当前状态将传递给State实例封装的函数(在本例中,vitalForce是我们的状态):

代码语言:javascript
复制
// makeLiveThing :: String -> State Integer Object
const makeLiveThing = part => State(
  vitalForce => {
    const unitOfForce = 1
    const remaining = vitalForce - unitOfForce

    return Pair(
      LivingPart(unitOfForce, part),
      remaining
    )
  }
)

现在我们已经有了创建LivingPart和处理状态事务(减少1)的方法,我们可以创建以下几个部分:

代码语言:javascript
复制
// rightLeg :: State Integer Object
const rightLeg =
  makeLiveThing('right-leg')

// leftArm :: State Integer Object
const leftArm =
  makeLiveThing('left-arm')

现在,连接这些State实例的任务来了。使用apply是正确的,因为当一个ADT同时拥有一个ap方法和一个of方法时,它被称为Applicative。当我们有一个Applicative时,我们可以认为该类型能够组合(2)不依赖于另一个实例的独立实例。我们只需要提供一种方法来告诉类型如何组合它。

通常,这是通过一个可以对ADT中包含的类型起作用的函数来完成的。在我们的示例中,它是一个Object,因此组合(2)对象的一种方法是使用Object.assigncrocks提供了一个名为assign的助手,它可以做到这一点,所以让我们将其引入:

代码语言:javascript
复制
const assign = require('crocks/helpers/assign')

现在我们有了组合内部值的方法,我们需要将这个函数“提升”到我们的State类型中,crocks还有一个函数可以在Applicatives上使用来提升和应用名为liftA2的ADT (2)实例的内部值。意思是“用两个实例将一个函数提升到一个应用程序中”。

因此,让我们把它也带来,然后创建一个函数,将用于连接(2) Parts

代码语言:javascript
复制
const liftA2 = require('crocks/helpers/liftA2')


// joinParts :: Applicative m => m Object -> m Object -> m Object
const joinParts =
  liftA2(assign)

现在使用这个函数,我们可以提升和连接这些部分,并使用我们的VitalForce运行结果

代码语言:javascript
复制
joinParts(rightLeg, leftArm)
  .runWith(10)
//=> Pair( { left-arm: { unitOfForce: 1 }, right-leg: { unitOfForce: 1 } }, 8 )

注意,结果在左边(组合的活部分)和右边的状态(剩余的VitalForce)中有结果。

以下是对上述内容的一些参考:

现在,我将展示一个简单的示例,说明如何设置单个State事务,以便从池中获取VitalForce。我不打算在这里详细解释,但是您应该能够在这个示例和State文档之间收集一些信息:

代码语言:javascript
复制
const State = require('crocks/State')

const constant = require('crocks/combinators/constant')
const mapProps = require('crocks/helpers/mapProps')

const { modify } = State

// decrementBy :: Integer -> Integer -> Integer
const decrementBy =
  x => y => y - x

// VitalForce :: { units: Integer }

// decUnitsBy :: Integer -> VitalForce -> VitalForce
const decUnitsBy = units =>
  mapProps({ units: decrementBy(units) })

// getVitalForce :: Integer -> State VitalForce VitalForce
const getVitalForce = units =>
  modify(decUnitsBy(units))
    .map(constant({ units }))

getVitalForce(3)
  .runWith({ units: 10 })
//=> Pair( { units: 3 }, { units: 7 } )

下面是这些包含的函数的一些文档:

因此,作为附带说明,我做一个LiveCode广播在这个频道,我将浏览这篇博客文章,并讨论如何在crocks中实现这一点,如果这是您感兴趣的事情的话。

希望这能帮上忙!

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51531825

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档