I am building an app based on domain-driven design using functional programming in javascript. I've settled on the sanctuary.js ecosystem as my tool of choice, but I'm facing some challenges in modelling types.
To put things in context, let's take the code below as an example:
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
})
My points of confusion follow:
- How do I define a simple type with sanctuary-def? From the example above, if I wanted to define a Amount type and use it in the Payment RecordType definition, how would I go about it? Would I have to define another RecordType for that?
- I may be wrong here, but my understanding so far is that the RecordType is equivalent to product types in functional programming. What is the way to define a sum type using sanctuary.js? The EnumType above comes close, but seems to be for simple values, as opposed to other types. More like, if I had two other types, Cash and Card, how would I model another type PaymentMethod as a choice between Cash and Card?
I'd be glad for any pointers. I'm pretty new to both functional programming and sanctuary.js so if there's something obvious I'm missing, I'd appreciate a nudge in the right direction.
Much thanks.
Let's consider payment methods. To keep the example simple, let's assume that a payment method is either cash, or a credit/debit card with an associated card number. In Haskell, we could define the type and its data constructors like so:
In order to define
PaymentMethodusing sanctuary-def we need to know how theCashandCarddata constructors are implemented. One is free to define these manually or to use a library such as Daggy. Let's write them by hand:Having defined the data constructors, we can then use
$.NullaryTypeto define thePaymentMethodtype:Note that because every
PaymentMethodvalue will have the special@@typeproperty, we can usetypeto determine whether an arbitrary JavaScript value is a member of thePaymentMethodtype.I realize that approximating that one line of Haskell in JavaScript is quite involved. I hope this example shows how the various pieces of the puzzle fit together.
We might like to define a case-folding function for
PaymentMethodlike so:Having defined
Cash,Card, andfoldPaymentMethodwe are able to construct and deconstructPaymentMethodvalues without worrying about implementation details. For example: