-
Notifications
You must be signed in to change notification settings - Fork 376
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add types #281
base: master
Are you sure you want to change the base?
Add types #281
Changes from all commits
31ef183
8099a87
935f203
15281ac
f5ddb0b
2e9e7fa
8b7dbd4
78b714c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -796,6 +796,143 @@ The `profunctor` method takes two arguments: | |
|
||
3. `promap` must return a value of the same Profunctor | ||
|
||
## Types | ||
|
||
In Fantasy Land, types are specified by an object containing a catamorphic | ||
method `cata`. `cata` has an arity matching the number of constructor functions | ||
belonging to each type. Each argument to `cata` is either: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For the benefit of people who don't know the difference between Types and Type Classes, I think we should elaborate the difference here to avoid confusion. Maybe a paragraph explaining the benefits in having a specification for both? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had considered placing the type specifications in a separate file but figure that could be a separate PR. I agree that an introductory paragraph contrasting the specification of algebras with that of types would be useful. Suggestions are welcome 😄 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it might be helpful to have a section describing sum and product types. Though I don't consider this specification a particularly good resource for JS devs new to FP, many find themselves here early on. |
||
|
||
1. a value corresponding to a nullary constructor | ||
|
||
1. Value arguments to `cata` must match the return type of `cata` itself. | ||
|
||
2. a function with an arity matching the number of arguments to the | ||
corresponding constructor function | ||
|
||
1. Function arguments to `cata` must return values of the same type as | ||
`cata` itself. | ||
|
||
For example | ||
```hs | ||
Identity a = { cata :: (a -> b) -> b } | ||
'------' ' '------' ' | ||
' ' ' ' - return type | ||
' ' ' | ||
' ' ' - destructor function | ||
' ' | ||
' ' - type variable | ||
' | ||
' - type name | ||
|
||
identity :: a -> Identity a | ||
'------' ' '--------' | ||
' ' ' | ||
' ' ' - return type | ||
' ' | ||
' ' - constructor argument | ||
' | ||
' - constructor name | ||
``` | ||
|
||
Libraries conforming to this specification may provide custom data constructors | ||
corresponding with the constructor functions. No provided constructors are | ||
required to share the names of the constructor functions defined herein. For | ||
example, instead of `Identity`, the constructor could be named `Id`. If custom | ||
constructors _are_ provided, they must return values which contain a `cata` | ||
method. This method must exhibit the same behaviour as described above. | ||
|
||
For example | ||
```js | ||
var identity = require('fantasy-land/identity'); | ||
|
||
function Id(x) { | ||
this.x = x; | ||
} | ||
Id.prototype['fantasy-land/cata'] = function cata(f) { | ||
return f(this.x); | ||
} | ||
|
||
// Alternatively | ||
Id.prototype['fantasy-land/cata'] = function cata(f) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When prefixing, should we also include the type name (e.g. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you talking about: S.cata(Id.of(1), /* How do I check the arity of this function? */...) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
return identity(this.x).cata(f); | ||
} | ||
|
||
(new Id(42)).cata(x => x) === identity(42).cata(x => x); | ||
``` | ||
|
||
### Maybe | ||
|
||
The `Maybe` type encodes the concept of optionality (Nothing and Just a). | ||
|
||
```hs | ||
Maybe a = { cata :: (b, a -> b) -> b } | ||
nothing :: Maybe a | ||
just :: a -> Maybe a | ||
``` | ||
|
||
A value which conforms to the Maybe specification must provide a `cata` method. | ||
|
||
The `cata` method takes two arguments: | ||
|
||
m.cata(f, g) | ||
|
||
1. `f` must be a nullary function. It is called in the `Nothing` case | ||
|
||
1. If `f` is not a nullary function or the return value of `f` does not | ||
match the return value of `cata`, the behaviour of `cata` is unspecified. | ||
|
||
2. `g` must be a unary function. It is called in the `Just` case | ||
|
||
1. If `g` is not a unary function or the return value of `g` does not match | ||
the return value of `cata`, the behaviour of `cata` is unspecified. | ||
|
||
### Either | ||
|
||
The `Either` type encodes the concept of binary possibility (Left a and Right b). | ||
|
||
```hs | ||
Either a b = { cata :: (a -> c, b -> c) -> c } | ||
left :: a -> Either a b | ||
right :: b -> Either a b | ||
``` | ||
|
||
A value which conforms to the Either specification must provide a `cata` method. | ||
|
||
The `cata` method takes two arguments: | ||
|
||
e.cata(f, g) | ||
|
||
1. `f` must be a unary function. It is called in the `Left` case | ||
|
||
1. If `f` is not a unary function or the return value of `f` does not match | ||
the return value of `cata`, the behaviour of `cata` is unspecified. | ||
|
||
2. `g` must be a unary function. It is called in the `Right` case | ||
|
||
1. If `g` is not a unary function or the return value of `g` does not match | ||
the return value of `cata`, the behaviour of `cata` is unspecified. | ||
|
||
### Tuple | ||
|
||
`Tuple` is the canonical product type and represents a structure containing two | ||
values (Tuple a b). | ||
|
||
```hs | ||
Tuple a b = { cata :: ((a, b) -> c) -> c } | ||
tuple :: (a, b) -> Tuple a b | ||
``` | ||
|
||
A value which conforms to the Tuple specification must provide a `cata` method. | ||
|
||
The `cata` method takes a single argument: | ||
|
||
t.cata(f) | ||
|
||
1. `f` must be a binary function | ||
|
||
1. If `f` is not a binary function or the return value of `f` does not match | ||
the return value of `cata`, the behaviour of `cata` is unspecified. | ||
|
||
## Derivations | ||
|
||
When creating data types which satisfy multiple algebras, authors may choose | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it might be better to use different names for each type, instead of using one for all, as for example if sanctuary or ramda wanted to implement it, i don't see what should be a type for
cata
.I would go with
either
forEither
,maybe
forMaybe
andrunIdentity for
Identity`.This way one could define maybe instance for Array for example, which might be useful in some cases.
Also regarding this general introduction of the
# Types
I think this part is a bit confusing, which as confusing as type ofcata
could be :DIf we instead go with special names for specific types, then we would have more precise description for each type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #280 for an alternate proposal. It is identical to what you propose and would allow the variety of polymorphism you're describing.