Functional programming sactionary.js中的数据建模挑战

Functional programming sactionary.js中的数据建模挑战,functional-programming,sanctuary,Functional Programming,Sanctuary,我正在使用javascript中的函数编程构建一个基于域驱动设计的应用程序。我已经选择saccession.js生态系统作为我的工具,但我在建模类型方面面临一些挑战 为了将事情放在上下文中,让我们以下面的代码为例: const{create}=require('sactionary')) const$=require('sactionary-def') const def=create({ checkTypes:process.env.NODE_env===='development', 环境:

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

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

const{create}=require('sactionary'))
const$=require('sactionary-def')
const def=create({
checkTypes:process.env.NODE_env===='development',
环境:$.env
})
常量货币=$.EnumType
(“货币”)
('http://example.com')
([‘美元’、‘欧元’))
const Payment=$.RecordType({
金额:$.Enumber,
货币:货币,,
方法:$.String
})
我的混淆点如下:

  • 如何用def定义简单类型?从上面的例子中,如果我想定义一个金额类型并在付款记录类型定义中使用它,我将如何进行?我需要为此定义另一个记录类型吗
  • 我在这里可能是错的,但到目前为止我的理解是,记录类型相当于函数式编程中的产品类型。使用sactionary.js定义sum类型的方法是什么?上面的EnumType非常接近,但似乎是针对简单值,而不是其他类型。更像是,如果我有另外两种类型,现金,我将如何在现金之间选择另一种类型的支付方法 我很乐意得到任何指点。我对函数式编程和saccession.js都是新手,所以如果有什么明显的地方我没有,我希望能朝着正确的方向前进


    非常感谢
    data PaymentMethod=现金|卡串
    
    为了使用SANCATION def定义
    PaymentMethod
    ,我们需要知道
    现金
    数据构造函数是如何实现的。您可以自由地手动定义或使用库,例如。让我们用手来写:

    //现金::支付方式
    常数现金={
    “@@type”:“我的包/PaymentMethod”,
    “标记名”:“现金”,
    };
    //卡片::字符串->付款方式
    常数卡=编号=>({
    “@@type”:“我的包/PaymentMethod”,
    “标记名”:“卡片”,
    “数字”:数字,
    });
    
    定义了数据构造函数之后,我们可以使用定义
    PaymentMethod
    类型:

    const$=require('sactionary-def');
    const type=require(‘类型标识符’);
    //PaymentMethod::Type
    常量PaymentMethod=$.NullaryType
    (“付款方式”)
    ('https://example.com/my-package#PaymentMethod')
    ([])
    (x=>type(x)==“我的套餐/付款方式”);
    
    请注意,由于每个
    PaymentMethod
    值都将具有特殊的
    @@type
    属性,因此我们可以使用来确定任意JavaScript值是否是
    PaymentMethod
    类型的成员

    我意识到,在JavaScript中接近Haskell的一行是相当复杂的。我希望这个例子展示了拼图的各个部分是如何组合在一起的


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

    //foldPaymentMethod::a->(字符串->a)->PaymentMethod->a
    const foldPaymentMethod=现金=>card=>paymentMethod=>{
    开关(paymentMethod.tagName){
    案例“现金”:返还现金;
    案例“卡”:退货卡(paymentMethod.number);
    }
    };
    
    定义了
    现金
    折叠式支付方法
    之后,我们可以构建和解构
    支付方法
    值,而无需担心实现细节。例如:

    >foldPaymentMethod('Cash')(数字=>`Card(${S.show(数字)})`)(现金)
    “现金”
    >foldPaymentMethod('Cash')(数字=>`Card(${S.show(数字)})`)(Card('246810214161820'))
    “卡(“246810214161820”)”
    
    值得一提的是,
    PaymentMethod
    不是枚举,因为
    Card
    值构造函数需要一个参数。@davidchambers谢谢。你的回答肯定会让你更清楚地知道每件事是怎么回事。目前,我创建了一个简单的类型,比如Amount,方法是首先创建一个数据构造函数,然后创建一个相应的$.NullaryType类型,该类型工作时没有任何错误。这条路对吗?另外,在哪些情况下我需要$.UnaryType或$.BinaryType?@bob谢谢您的输入。注意。
    $.NullaryType
    用于定义采用一个类型参数的类型构造函数,例如
    数组a
    可能是a
    ,以及
    树a
    <代码>$。BinaryType用于定义二进制类型构造函数,例如
    a b
    对a b