首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >sanctuary.js中的数据建模挑战

sanctuary.js中的数据建模挑战
EN

Stack Overflow用户
提问于 2020-06-10 08:31:08
回答 1查看 255关注 0票数 1

我正在构建一个基于领域驱动设计的应用程序,使用javascript中的函数编程。我已经确定sanctuary.js生态系统是我选择的工具,但我在建模类型方面面临一些挑战。

为了将内容放在上下文中,让我们以下面的代码为例:

代码语言:javascript
复制
  const { create } = require('sanctuary')
  const $ = require('sanctuary-def')
  const def = create({
    checkTypes: process.env.NODE_ENV === 'development',
    env: $.env
  })

  const Currency = $.EnumType
    ('Currency')
    ('http://example.com')
    (['USD', 'EUR'])

  const Payment = $.RecordType({
    amount: $.PositiveNumber,
    currency: Currency,
    method: $.String
  })

我的困惑之处如下:

  1. 我如何定义一个简单的类型与避难所-def?从上面的例子中,如果我想定义一个类型并在Payment RecordType定义中使用它,我将如何处理它?我需要为此定义另一个RecordType吗?
  2. 我可能错了,但到目前为止,我的理解是,在函数式编程中,RecordType等同于产品类型。使用sanctuary.js定义和类型的方法是什么?上面的EnumType比较接近,但似乎是用于简单值,而不是其他类型。更像是,如果我有另外两种类型,CashCard,我将如何在CashCard之间建立另一种类型的?

我很乐意给你指点。我对函数式编程和sanctuary.js都很陌生,所以如果有明显的东西我错过了,我会很感激在正确的方向上推动一下。

非常感谢。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-06-10 10:32:59

让我们考虑一下支付方法。为了保持示例的简单性,让我们假设一种支付方法要么是现金,要么是带有相关卡号的信用卡/借记卡。在Haskell中,我们可以定义类型及其数据构造函数,如下所示:

代码语言:javascript
复制
data PaymentMethod = Cash | Card String

为了使用sanctuary定义PaymentMethod,我们需要知道CashCard数据构造函数是如何实现的。您可以手动定义这些库或使用库(如达吉 )。让我们用手写:

代码语言:javascript
复制
//    Cash :: PaymentMethod
const Cash = {
  '@@type': 'my-package/PaymentMethod',
  'tagName': 'Cash',
};

//    Card :: String -> PaymentMethod
const Card = number => ({
  '@@type': 'my-package/PaymentMethod',
  'tagName': 'Card',
  'number': number,
});

定义了数据构造函数之后,我们可以使用$.NullaryType定义PaymentMethod类型:

代码语言:javascript
复制
const $ = require ('sanctuary-def');
const type = require ('sanctuary-type-identifiers');

//    PaymentMethod :: Type
const PaymentMethod = $.NullaryType
  ('PaymentMethod')
  ('https://example.com/my-package#PaymentMethod')
  ([])
  (x => type (x) === 'my-package/PaymentMethod');

注意,因为每个PaymentMethod值都具有特殊的@@type属性,所以我们可以使用type来确定任意的JavaScript值是否是PaymentMethod类型的成员。

我意识到,在JavaScript中近似Haskell的一行是相当重要的。我希望这个例子能显示出拼图的各个部分是如何结合在一起的。

我们可能希望为PaymentMethod定义一个案例折叠函数,如下所示:

代码语言:javascript
复制
//    foldPaymentMethod :: a -> (String -> a) -> PaymentMethod -> a
const foldPaymentMethod = cash => card => paymentMethod => {
  switch (paymentMethod.tagName) {
    case 'Cash': return cash;
    case 'Card': return card (paymentMethod.number);
  }
};

定义了CashCardfoldPaymentMethod之后,我们就可以构造和解构PaymentMethod值,而不必担心实现细节。例如:

代码语言:javascript
复制
> foldPaymentMethod ('Cash') (number => `Card (${S.show (number)})`) (Cash)
'Cash'

> foldPaymentMethod ('Cash') (number => `Card (${S.show (number)})`) (Card ('2468101214161820'))
'Card ("2468101214161820")'
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62299146

复制
相关文章

相似问题

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