我正在使用javascript中的函数式编程构建一个基于领域驱动设计的应用程序。我已经确定了sanctuary.js生态系统作为我的首选工具,但我在建模类型上面临一些挑战。
为了说明问题,我们以下面的代码为例。
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
})
我的困惑点如下:
我很高兴得到任何提示。我对函数式编程和sanctuary.js都很陌生,所以如果有什么明显的东西我错过了,我会很感激在正确的方向上的推移。
非常感谢。
让我们考虑一下支付方式。为了保持例子的简单性,我们假设支付方式是现金,或者是带有关联卡号的信用卡(creditdebit card)。在 Haskell 中,我们可以像这样定义类型和它的数据构造函数。
data PaymentMethod = Cash | Card String
为了定义 PaymentMethod
使用sanctuary-def时,我们需要知道如何使用这些功能。Cash
和 Card
数据构造器。人们可以自由地手动定义这些构造函数,或者使用一个库,如 妲己. 让我们手写它们。
// 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
型。
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
像这样。
// foldPaymentMethod :: a -> (String -> a) -> PaymentMethod -> a
const foldPaymentMethod = cash => card => paymentMethod => {
switch (paymentMethod.tagName) {
case 'Cash': return cash;
case 'Card': return card (paymentMethod.number);
}
};
已定义 Cash
, Card
和 foldPaymentMethod
我们能够构建和解构 PaymentMethod
值,而不用担心实现细节。例如:
> foldPaymentMethod ('Cash') (number => `Card (${S.show (number)})`) (Cash)
'Cash'
> foldPaymentMethod ('Cash') (number => `Card (${S.show (number)})`) (Card ('2468101214161820'))
'Card ("2468101214161820")'