Skip to content

Instantly share code, notes, and snippets.

@dead-claudia
Created September 19, 2015 05:05
Show Gist options
  • Save dead-claudia/31f0e25310396736185c to your computer and use it in GitHub Desktop.
Save dead-claudia/31f0e25310396736185c to your computer and use it in GitHub Desktop.
Experiment with maybe types, the pipeline operator, and the binding operator, in both LiveScript and proposed JavaScript.
import * as http from "http"
import * as https from "https"
import pipe from "./pipe.js"
import {then, orElse} from "./maybe.js"
const error = message => () => { throw new TypeError(message) }
const is = (obj, type) => typeof obj === type
class Settings {
constructor(port, ctor) {
this._port = port
this._ctor = ctor
}
port(port) {
return this._port
->then(p => p->is("number") ? p : null)
->orElse(error("port should be a number"))
->then(port => new Settings(port, this._ctor))
}
construct(ctor) {
return this._ctor
->then(ctor => {
if (ctor->is("function")) return new Settings(this._port, ctor)
if (ctor->is("object") && ctor.createServer->is("function")) {
return new Settings(this._port, ctor::createServer)
}
})
->orElse(error(`constructor should be either a function or an object
with a createServer method`))
}
http() { return new Settings(this._port, http.createServer) }
https(opts) {
return new Settings(this._port, cb => https.createServer(opts, cb))
}
create() {
return this._port
->then(port => this._ctor->then(ctor => {port, ctor}))
->orElse(error(`There should be both a port and constructor at
initialization`))
->then(({port, ctor}) => pipe(port, ctor))
}
}
export default Settings::[new]
# LiveScript already has similar as well. It just compiles the pipe operator
# to a call to a 1-argument function (which makes it less useful with JS utility
# libraries).
require! {
http
https
'./pipe': pipe
'./maybe': m
}
error = (message) -> -> throw new TypeError message
isa = (obj, type) --> typeof obj == type
class Settings
(@_port, @_ctor) ->
port: (port) ->
@_port
|> m.map ~> if type it, 'number' then it else null
|> m.else error 'port should be a number'
|> m.map ~> new Settings it, @_ctor
construct: (ctor) ->
@_ctor
|> m.map ~>
| it `isa` 'function' => new Settings @_port, ctor
| it `isa` 'object' and it.createServer `isa` 'function' =>
new Settings @_port, -> ctor.createServer ...&
|> m.else error 'constructor should be either a function or an object
with a createServer method'
http: -> new Settings @_port, http.createServer
https: (opts) -> new Settings @_port, -> https.createServer opts, it
create: ->
@_port
|> m.map (port) ~> @_ctor |> m.then (ctor) -> {port, ctor}
|> m.else error 'There should be both a port and constructor at
initialization'
|> m.then ({port, ctor}) -> pipe port, ctor
module.exports = -> new Settings ...
const identity = x => x
export const then = (x, some, none = identity) => x != null ? some(x) : none()
export const orElse = (x, f) => x->then(identity, f)
id = -> it
exports.then = (some, none, x) --> if x? then some x else none!
exports.map = (f, x) --> exports.then x, f, id
exports.else = (x, f) --> exports.then x, id, f
@jasmith79
Copy link

You mentioned that this has been proposed for javascript, has there really been a proposal for a pipe operator?

@Syynth
Copy link

Syynth commented Nov 6, 2015

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment