npm i stick-js # or yarn
cat >.babelrc <<EOT
{"presets": ["babel-preset-es2015", "stage-0"], "plugins": [
"babel-plugin-operator-overload"
]}
EOT
// --- src/index.js
defineBinaryOperator ('|', (...args) => pipe (...args))
defineBinaryOperator ('<<', (...args) => compose (...args))
defineBinaryOperator ('>>', (...args) => composeRight (...args))
import { pipe, compose, composeRight, map, join, sprintf1 } from 'stick-js'
import { green } from 'chalk'
; [1, 2, 3]
| map (x => x + 1)
| join ('/')
| green
| sprintf1 ('The answer is %s')
| console.log
// ---
node_modules/.bin/babel -d lib src
node lib/index.js
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [[
"env",
{ "modules": false },
]],
plugins: [
'operator-overload',
],
},
},
},
...
]
...
}
A way to start using the pipe (or 'stick') operator today while proposal TC39/proposal-pipeline-operator is still being fleshed out.
Companion operators >>
and <<
for composing. Often a pipeline can be
made more interesting and reusable by abstracting away the data to leave a
'point-free' form. See below for many examples of this.
Note that we use |
, not |>
, which is not only easier to overload but
far more pleasant to work with, and which will still work even if/when the
proposal is accepted.
A toolkit of functions centered around this pattern, and a number of idioms which they facilitate; in particular, we provide several ways to replace blocks of statements by referentially transparent expressions, and work with prototypes, factories, mutable and immutable data, and more.
You can use our functions, or your own favorite library (Ramda, lodash/fp, etc.), or mix and match as you like.
Practical examples and advice which will hopefully be of use to TC39, after using these idioms in many projects for about a year. In particular, we hope to make a strong case that composition operators should be considered in addition to a pipeline operator.
The overloading is made possible thanks to the great babel-plugin-operator-overload library by Jussi Kalliokoski (@jussi-kalliokoski).
A few examples:
import chalk from 'chalk'
; [1, 2, 3]
| map (x => x + 1)
| join ('/')
| chalk.green
| sprintf1 ('The answer is %s')
| log // outputs 'The answer is 2/3/4' (colorfully)
const isInteger = x => x === Math.floor (x)
const ifInteger = isInteger | ifPredicate
; [3.5, 4, 4.2]
| map (ifInteger (
x => x + 1,
always ('nothing'),
))
// ['nothing', 5, 'nothing']
const convertFahrenheit = fah => lets (
_ => (fah - 32) / 9 * 5, // (1) celsius
(cel) => cel + 273, // (2) kelvin
(cel, kel) => [cel, kel], // (3) result
)
convertFahrenheit (86) // [30, 303]
const checkVal = condS ([
4 | eq | guard (sprintf1 ('%s was exactly 4')),
4 | lt | guard (sprintf1 ('%s was less than 4')),
4 | gt | guard (sprintf1 ('%s was more than 4')),
otherwise | guardV ("error, this shouldn't happen"),
])
; [3, 4, 5]
| map (checkVal)
| join (' | ')
// 3 was less than 4 | 4 was exactly 4 | 5 was more than 4
// ------ dog.js
const proto = { speak () { 'Hi from ' + this.name }}
export default proto | factory
// ------ main.js
import Dog from './dog'
Dog.create ({ name: 'Caesar', }).speak () // 'Hi from Caesar'
And much more.
There are many examples in the src/examples folder.
The WebGL example lives in its own repository, and you can see it running here.
It is based on the amazing raindrops demo by Lucas Bebber (@lbebber), which simulates raindrops on glass, ported to use a more functional style and stick idioms.
The example called 'intercepted' is the most advanced: it puts together a lot of the ideas explained below, and adds lazy lists, composing promise-based functions, and a 'frontend app' in the console analogous to React & Redux.
// --- source files must begin with this header.
defineBinaryOperator ('|', (...args) => pipe (...args))
defineBinaryOperator ('<<', (...args) => compose (...args))
defineBinaryOperator ('>>', (...args) => composeRight (...args))
import {
pipe, compose, composeRight,
// --- /header
map, join, sprintf1,
} from 'stick-js'
import { green, } from 'chalk'
const { log, } = console
; [1, 2, 3]
| map (x => x + 1)
| join ('/')
| green
| sprintf1 ('The answer is %s')
| log // outputs 'The answer is 2/3/4' (colorfully)
a | b
is simply an equivalent way of writing b (a)
A really simple idea, with some pretty far-reaching consequences.
(What if I really want to do bitwise math, you ask? Don't worry, you still can: see below).
// --- reminder: source files must begin with this.
// --- from here on out we'll omit it in the examples.
defineBinaryOperator ('|', (...args) => pipe (...args))
defineBinaryOperator ('<<', (...args) => compose (...args))
defineBinaryOperator ('>>', (...args) => composeRight (...args))
import {
pipe, compose, composeRight,
map, join, split,
} from 'stick-js'
const multiply = x => y => x * y
const double = multiply (2) // or 2 | multiply
3 | double // 6
double (3) // 6
3 | multiply (4) // 12
const capitaliseFirstLetter = x => x[0].toUpperCase () + x.slice (1)
'just a perfect day'
| split (' ') // split (' ') is a function
| map (capitaliseFirstLetter) // map (capitaliseFirstLetter) is also a function
| join (' ') // ... you get the picture.
// 'Just A Perfect Day'
All curried functions provided by stick-js can be called using either of 2 currying styles.
This would be a good time to read up on curried functions if you're not familiar with them.
we will refer to this sort of function and calling style as 'manual':
const f = a => b => c => a + b + c // call like f (1) (2) (3)
and this sort as 'normal':
const g = R.curry ((a, b, c) => a + b + c) // call like g (1) (2) (3)
// or g (1, 2, 3)
// or g (1, 2) (3)
// or g (1) (2, 3)
// etc.
Calling:
import { map, } from 'stick-js'
const double = x => x * 2
map (double, [1, 2, 3]) // [2, 4, 6] (normal style)
map (double) ([1, 2, 3]) // [2, 4, 6] (manual style)
; [1, 2, 3] | map (double) // [2, 4, 6] (manual style with stick)
For extra performance you can also limit yourself to the manual style (see below).
We recommend using a space before the parentheses of a function call. Admittedly it looks pretty strange at first, but we find that it makes everything much clearer when you get used to it, in particular with the manual currying style.
You might also want to check out a vertical alignment plugin. The author
uses vim-easy-align
by @junegunn.
import { sprintfN, sprintf1, } from 'stick-js'
3 | sprintf1 ('4 - 1 is %s') // '4 - 1 is 3'
'N' is a marker meaning an array is expected.
; [4, 3]
| sprintfN ('%s - 1 is %s') // same.
'V' means a value is expected, to disambiguate cases where a function also fits.
import { timesV, timesF, } from 'stick-js'
const { random, } = Math
3 | timesV (4) // [3, 3, 3, 3]
random | timesF (4) // [<random-num>, <random-num>, <random-num>, <random-num>]
random | timesV (4) // [random, random, random, random]
Note that the last one stores the function 4 times in the array.
random | timesV (4) | map (invoke) // [<random-num>, <random-num>, <random-num>, <random-num>]
'M' means the data is being mutated. In JS we of course work with mutable data all the time.
import { appendTo, appendToM, } from 'stick-js'
const a = [1, 2, 3]
const b = 4 | appendTo (a) // functional style: the array is cloned.
b === a // false
const a = [1, 2, 3]
const b = 4 | appendToM (a) // non-functional style: the array is mutated.
b === a // true
const webGLContext = { ... a complicated object ... }
webGLContext | mergeM ({ someProp: false, }) // you probably want mutable here.
And there are a few more which we'll see along the way.
ok (x)
is false if x
is null
or undefined
. Every other input returns
true
.
import { map, ok, notOk, ifOk, } from 'stick-js'
const { log, } = console
; [0, false, '', null, void 8]
| map (ok) // [true, true, true, false, false]
; [0, false, '', null, void 8]
| map (notOk) // [false, false, false, true, true]
Something we see a lot in JS is:
let answer
if (someVar !== undefined && someVar !== null) {
answer = someVar + 1
} else {
answer = 'nothing'
}
This can vastly improved using an 'anaphoric if' and a stick idiom:
import { add, always, } from 'stick-js'
const add1 = 1 | add // or add (1)
const answer = someVar | ifOk (add1, 'nothing' | always)
Explanation: ifOk
takes two functions -- a 'then' function and an 'else' function.
In the 'ok' case, the value being tested is passed to the function. (This
bound value is sometimes called an 'anaphor').
const add1IfYouCan = val => val | ifOk (
// `that` refers to `val`
that => that + 1,
// no value is passed.
_ => 'nothing',
)
This can be further condensed, using 'point-free style' (see below) and the always
function:
const add1IfYouCan = ifOk (1 | add, 'nothing' | always)
Usage:
const answer = someVar | add1IfYouCan
; [0, 10, null, void 8]
| map (add1IfYouCan) // [1, 11, 'nothing', 'nothing']
A common pattern is when the argument to a function is passed immediately into a pipe:
const add1IfYouCan = x => x | ifOk (add1, 'nothing' | always)
Since x
does not appear anywhere else in the expression, we can simply remove it, along with the function argument:
const add1IfYouCan = ifOk (add1, 'nothing' | always)
This is often called 'point-free' style. It means the function arguments and the data being passed through the pipeline have been abstracted away (and has nothing to do with dots, despite the name).
If the pipe chain consists of more than 1 link …
const { dot, sprintf1, tap, }
const { log, } = console
const add1IfYouCan = x => x
| ifOk (add1, 'nothing' | always)
| String // conversion using type constructor
| dot ('toUpperCase')
| sprintf1 ('The answer is %s')
| tap (log) // outputs 'The answer is 1', 'The answer is NOTHING', ...
… then we remove the x => x
and change all the |
to >>
const add1IfYouCan =
ifOk (add1, 'nothing' | always) // (1)
>> String // (2)
>> dot ('toUpperCase') // (3)
>> sprintf1 ('The answer is %s') // (4)
>> tap (log) // (5)
The following pattern always holds:
a | b | c = a | (b >> c)
So when the chains start to get long (as above), you can cut pieces out using this property. For example, you can refactor lines 2-4 into a new function:
// --- convert input to String, make uppercase, perform sprintf.
const processString = String
>> dot ('toUpperCase')
>> sprintf1 ('The answer is %s')
And splice it back in:
const add1IfYouCan = x => x
| ifOk (add1, 'nothing' | always)
| processString
| tap (log)
Or
const add1IfYouCan =
ifOk (add1, 'nothing' | always)
>> processString
>> tap (log)
ifOk
is a convenience for ifPredicate (ok)
or ok | ifPredicate
.
There is also a 'when' form, which has no 'else' branch.
import { add, whenOk, } from 'stick-js'
const add1 = 1 | add // or add (1)
3 | whenOk (add1) // 4
null | whenOk (add1) // undefined
The selection of if
and when
functions we provide is intentionally skimpy, to encourage you to compose your own.
const { floor, } = Math
// --- predicate to match integers.
const isInteger = x => x === floor (x)
// --- or how about
// import { eq, } from 'stick-js'
// const isInteger = x => x | floor | eq (x)
// --- or if you're getting bored:
// import { timesV, asteriskN, passToN, } from 'stick-js'
// const arrowSnd = f => timesV (2) >> asteriskN ([id, f])
// const isInteger = arrowSnd (floor) >> passToN (eq)
// --- now compose it into an anaphoric if:
const ifInteger = isInteger | ifPredicate
// --- now use it:
const add1 = add (1)
; [3.5, 4, 4.2]
| map (ifInteger (add1, 'nothing' | always))
// ['nothing', 5, 'nothing']
More complicated predicates:
const both = (f, g) => againstAll ([f, g])
const isOdd = x => x % 2
const isOddInteger = both (isInteger, isOdd)
const ifOddInteger = isOddInteger | ifPredicate
; [3.5, 4, 5, 5.5]
| map (ifOddInteger (
add1,
'nothing' | always,
))
// ['nothing', 'nothing', 6, 'nothing']
; [3.5, 4, 5, 5.5] | map (isOddInteger)
// [false, false, 1, false]
Note that againstAll
returns the return value of the last matching
function, hence 1
in the last example. This is because it can be useful to
have that value, and it's analogous to how the short-circuit &&
works.
To convert a truthy expression to a strict one: simply compose it with the
type constructor Boolean
.
const both = (f, g) => againstAll ([f, g]) >> Boolean
Or, you could add === true
to the end of the isOdd
function.
Note that ifPredicate
and whenPredicate
match on truthiness, not strict
truth. Rationale: that is how the native filter
works, and JS's if
operator, and many other tools in e.g. Ramda. And converting truthy to
strict Boolean is trivial.
Our map
function is capped at one argument, meaning the map routine only
gets the value and not the index or the collection.
import { map, addIndex, addCollection, } from 'stick-js'
; [4, 5, 6]
| map ((x, idx) => idx) // [undefined, undefined, undefined]
But:
const mapWithIndex = map | addIndex
const mapWithCollection = map | addCollection
; [4, 5, 6]
| mapWithIndex ((x, idx) => idx) // [0, 1, 2]
; [4, 5, 6]
| mapWithCollection ((x, coll) => coll) // [[4, 5, 6], [4, 5, 6], [4, 5, 6]]
; [4, 5, 6]
| (map | addIndex | addCollection) ((x, idx, coll) => ...)
; [4, 5, 6]
| (map | addCollection | addIndex) ((x, coll, idx) => ...)
We can also enhance our merge functions, to deal with conflicts:
import { mergeWith, mergeToSym, } from 'stick-js'
const chooseTgt = (src, tgt) => tgt
const chooseSrc = (src, tgt) => src
// --- choose target value on conflict
const mergeChooseTgt = mergeToSym | mergeWith (chooseTgt)
// --- choose source value on conflict
const mergeChooseSrc = mergeToSym | mergeWith (chooseSrc)
const os = { name: 'source name', }
const ot = { name: 'target name', }
os | mergeChooseSrc (ot) // 'source name'
os | mergeChooseTgt (ot) // 'target name'
Or to only merge if certain conditions hold:
import { mergeWhen, eq, } from 'stick-js'
const { floor, } = Math
const isInteger = x => x | floor | eq (x)
const srcIsInteger = (src, tgt) => src | isInteger
const mergeToWhenSrcIsInteger = mergeToSym | mergeWhen (srcIsInteger)
const os = { val: 2.2, vil: 3, vol: 3.5, }
const ot = { val: 25, vil: 25, vol: 25, vel: 42, }
os | mergeTo (ot) // { val: 2.2, vil: 3, vol: 3.5, vel: 42, }
os | mergeToWhenSrcIsInteger (ot) // { val: 25, vil: 3, vol: 25, vel: 42, }
(We're dying to see a port to Hungarian, too)
Once you master this, the usage becomes intuitive and greatly reduces the need to look things up.
(Motivation: what's the argument order of append
, times
, and subtract
in your favorite library?)
import {
sprintfN, sprintf1, mergeTo, merge, prependTo, prepend,
appendTo, append, bindPropTo, bindProp, bindTo, bind, invoke,
} from 'stick-js'
const tgt = { thing: 'sandwich', want: 'no thanks', }
const src = { want: 'yes please', }
When a function name ends in a preposition, for example, ‘To’, the identifier to the right is the object of the preposition.
Read this as ‘merge src to tgt’
src | mergeTo (tgt) // { thing: 'sandwich', want: 'yes please', }
The same function name without the preposition means that the identifier to the right is the object of the verb ‘merge’.
Read this as: ‘merge src to tgt’
tgt | merge (src) // { thing: 'sandwich', want: 'yes please', }
4 | appendTo ([1, 2, 3]) // [1, 2, 3, 4]
; ([1, 2, 3]) | append (4) // [1, 2, 3, 4]
0 | prependTo ([1, 2, 3]) // [0, 1, 2, 3]
; ([1, 2, 3]) | prepend (0) // [0, 1, 2, 3]
const dog = {
name: 'Caesar',
speak () { return 'My name is ' + this.name },
}
const cat = {
name: 'Fritz',
speak () { throw new Error },
}
const f = 'speak' | bindPropTo (dog)
f () // 'My name is Caesar'
// --- 'bind prop "speak" to object'
'speak' | bindPropTo (dog) | invoke // same
// --- also 'bind prop "speak" to object'
dog | bindProp ('speak') | invoke // same
dog.speak | bindTo (dog) | invoke // same
// cat.speak () // Error
dog.speak | bindTo (cat) | invoke // 'My name is Fritz'
cat | bind (dog.speak) | invoke // 'My name is Fritz'
// --- 'call this function on this context', i.e., bind and call.
; ({}.toString) | callOn (3) // '[object Number]'
// --- 'provide this context to this function'
; 3 | provideTo ({}.toString) // '[object Number]'
Note that this fits the a | b | c
pattern:
dog.speak | bindTo (cat) | invoke // 'My name is Fritz'
So we can also write it as a | (b >> c)
:
dog.speak | (bindTo (cat) >> invoke) // 'My name is Fritz'
In fact bindTo (x) >> invoke
is already provided under the name callOn
,
and its inverse provideTo
:
dog.speak | callOn (cat) // 'My name is Fritz'
cat | provideTo (dog.speak) // 'My name is Fritz'
Some other miscellaneous examples.
// --- '3 to the 4th'
3 | toThe (4) // 81
// --- 'divide 3 by 6' or '3 divided by 6'
3 | divideBy (6) // 0.5
// --- 'divide 3 into 6'
3 | divideInto (6) // 2
// --- 'subtract 3 from 4'
3 | subtractFrom (4) // 1
// --- 'subtract 4 from 3'
3 | subtract (4) // -1
// --- '3 minus 4'
3 | minus (4) // -1
import {
map, side1, appendM, append, prependM, prepend,
} from 'stick-js'
Chaining with the .
will often not do what you want.
; [2, 3, 4]
.push (5)
.unshift (1) // error, return value of previous line was 5
But this will:
const push = 'push' | side1
const unshift = 'unshift' | side1
The 1 in side1 refers to the arity of the function, i.e., the exact number of arguments it expects. When working with functions in this way it's important to specify this.
.push
and .unshift
, both methods of Array.prototype
, expect exactly
one argument, hence side1
in both cases.
; [2, 3, 4]
| push (5)
| unshift (1) // [1, 2, 3, 4, 5]
// --- using stick functions for mutable data:
; [2, 3, 4]
| appendM (5)
| prependM (1)
// --- using stick functions for immutable data:
; [2, 3, 4]
| append (5) // new array [2, 3, 4, 5]
| prepend (1) // new array [1, 2, 3, 4, 5]
You can insert tap
anywhere in the chain, which is guaranteed not to mess
with the pipeline no matter what it returns:
const double = x => x * 2
; [1, 2]
| map (double) // [2, 4]
| tap (x => console.log (x)) // still [2, 4], performs side-effect (printing)
| tap (x => [100, 200]) // still [2, 4], for demonstration only
| join (',')
// '2,4'
Without the first tap
, this would have been an error, because
console.log
returns undefined
.
tap
is useful to signal the intention of performing side effects or IO. It
is also really useful for debugging. And our side
family of functions use
tap
under the hood.
import {
factory, factoryProps,
factoryStatics,
} from 'stick-js'
// --- dog.js:
const proto = {
init () {
...
return this
},
breathe () { return 'huff' },
whoami () { return this.name },
getType () { return this.type },
}
const props = {
type: 'dog',
name: undefined,
}
// --- basic:
export default proto | factory
// --- variants:
export default proto | factory | factoryProps (props)
export default proto | factory | factoryStatics ({ ... }) | factoryProps (props)
// ------ main.js
import Dog from './dog'
const dog = Dog.create ()
// const dog = Dog.create ().init () // useful in practice
dog.breathe () // 'huff'
dog.type // 'dog', if `factoryProps` used
dog.getType () // 'dog', same
dog.whoami () // undefined, because no default.
const dog2 = Dog.create ({ name: 'garfunkel', })
dog2.whoami () // 'garfunkel', thanks to args to create
// ------ animal.js:
import {
factory, factoryStatics, mixinM, mixinPreM,
factoryProps,
ifPredicate,
} from 'stick-js'
const isOdd = x => x % 2 !== 0
const ifOdd = isOdd | ifPredicate
// --- a 'base' object (animal)
const proto = {
init () {
...
return this
},
move () {
return this.numLegs | ifOdd (
_ => 'hobble',
_ => 'gait',
)
},
breathe () { return 'huff' },
speak () { 'not implemented' | die },
getType () { return this.type },
}
const props = {
type: 'animal',
numLegs: undefined,
}
export default proto | factory | factoryProps (props)
// ------ cheater.js:
// --- some orthogonal functionality
const proto = {
cheat: howMuch => 'I cheat ' + howMuch,
}
export default proto | factory
// ------ dog.js:
import {
sprintf1,
factory,
} from 'stick-js'
import Animal from './animal'
import Cheater from './cheater'
const { proto: animalProto, } = Animal
const { proto: cheaterProto, } = Cheater
// --- a composite object (dog), extended from animal, with extra functions mixed in.
const proto = {
init () {
...
return this
},
speak () { return this.name | sprintf1 ('Dog %s says woof') }
}
const props = {
type: 'dog',
numLegs: 4,
name: undefined,
}
export default proto
| mixinPreM (animalProto)
| mixinM (cheaterProto)
| factory
| factoryProps (props)
// ------ main.js
import Dog from './dog'
const dog = Dog.create ({ name: 'garfunkel', })
// const dog = Dog.create ({ name: 'garfunkel', }).init () // with init
dog.breathe () // 'huff' (from animal)
dog.getType () // 'dog' (function from animal, property from dog)
dog.speak () // 'Dog garfunkel says woof' (function from dog, property from instance initialisation)
dog.cheat ('a bit') // 'I cheat a bit' (from cheater)
Stick idioms:
const breathe = dot ('breathe')
const getType = dot ('getType')
const speak = dot ('speak')
const cheat = dot1 ('cheat')
const init = side ('init')
const create = dot1 ('create')
const dog = Dog
| create ({ name: 'garfunkel', })
| init
dog | breathe
dog | getType
dog | speak
Dog | create ({ name: 'garfunkel', })
| init
| cheat
We provide a functional style for working with objects the way JS was
designed to: using prototypical inheritance and Object.create. We hope to
show you that the new
keyword and 'classes' and all the baggage they bring
are unnecessary, and that they obfuscate the way that it actually works.
We provide a simple abstraction for factories, with as little sugar and magic as possible, and encourage you to mix and match the components to do exactly what you need.
To recap: you create an object in JS by first building a prototype object, consisting of only functions.
const animalProto = {
breathe () { return 'huff' },
speak () { throw new Error },
...
}
To make an animal
instance, you pass this prototype object to Object.create
,
assign some methods and/or properties. If you wish you can use
Object.create
again (and again) before assigning properties, copy in some
more values, use Object.create
again, and so on.
(Nothing will stop you from using Object.create
on an object with
non-method properties in it, and it will probably do what you want, but it's
best avoided -- add your properties to the last object in the chain).
We encapsulate this process with the notion of a factory, which is an object which knows how to spawn objects of a certain sort.
import { factory, } from 'stick-js'
const animalProto = {
breathe () { return 'huff' },
speak () { throw new Error },
...
}
const Animal = animalProto | factory // other idioms might call it `animal` or `animalFactory`
const animal1 = Animal.create ()
const animal2 = Animal.create ()
animal1.breathe () // 'huff'
animal2.breathe () // 'huff'
animal2.speak () // Error
To add properties:
const animalProps = {
type: 'animal',
size: undefined,
numLegs: undefined,
}
And we recommend always having an init
method, which you will almost certainly
need. myFactory.create ().init ()
becomes a well-worn pattern.
const isOdd = x => x % 2 !== 0
const ifOdd = isOdd | ifPredicate
const animalProto = {
init () {
...
return this
},
breathe () { return 'huff' },
speak () { throw new Error },
move () {
return this.numLegs | ifOdd (
_ => 'hobble',
_ => 'gait',
)
},
}
const Animal = animalProto | factory | factoryProps (animalProps)
On create
, the properties which are 'ok' will get copied in to the new
object.
The others are there for documentation: put them here, not peppered
throughout the methods. Do use undefined
for props that are waiting to be
defined, which is arguably better than null
and definitely better than
false
. Use void 8
or your very own favorite number to impress … no one.
const animal = Animal.create ().init ()
animal.type // 'animal'
animal.size // undefined
You can pass an object to create
to initialise properties. These will be
copied in after the props that were passed to factoryProps
are.
const bigBiped = Animal.create ({ size: 'big', numLegs: 2, }).init ()
You can also eliminate the dots entirely:
const create = dot1 ('create')
const init = side ('init')
const move = dot ('move')
const speak = dot ('speak')
Animal | create ({ size: 'small', numLegs: 2, })
| init
| move // 'gait'
Note that by using side
for init
we are assured that the instance is
passed down through the pipe and not the return value of init
(although in
this case, init
returns this
, so dot
would have worked too.) create
and move
definitely need dot
and not side
.
To extend Animal
to the obligatory Dog
find the Animal
prototype
(if animalProto
is not in scope).
const animalProto = Animal.proto
Or
const animalProto = Animal.create ().__proto__ // might not be available in all runtimes
Create it, add dog methods, and make a new factory:
const dogProto = animalProto
| Object.create
| mergeM ({
speak () { return this.loud ? 'WOOF' : 'woof' },
})
const dogProps = {
numLegs: 4,
loud: undefined,
}
const Dog = dogProto | factory | factoryProps (dogProps)
; [true, false]
| map ((isLoud) => Dog
| create ({ loud: isLoud, })
| (dog => [dog.speak (), dog.breathe (), dog.move ()])
)
// [['WOOF', 'huff', 'gait'], ['woof', 'huff', 'gait']]
Note that we can call methods of both Animal
and Dog
now.
const Dog = dogProto | mixinM (animalProto) | factory | factoryProps (dogProps)
Working with mixins is tricky. At some point, there will be namespace conflicts and it's not always obvious which version should win out -- and you have to decide how you want to deal with that.
But you have all the tools now to specify exactly how you want it to work. This is where JS shines: freedom.
const Dog = dogProto | mixinPreM (animalProto) | factory | factoryProps (dogProps)
const dog1 = Dog | create ({})
dog1 | breathe // 'huff'
const Dog = dogProto | mixinPreM (animalProto) | factory | factoryProps (dogProps)
Dog.create ({}) | speak // 'woof'
We mixed the animal into the dog as a 'pre' mixin, meaning that on name
conflicts, Dog's version will win. If we had used mixinM
instead of
mixinPreM
:
const Dog = dogProto | mixinM (animalProto) | factory | factoryProps (dogProps)
Dog | create ({})
| speak // Error, this is Animal's version.
Non-pre mixins are useful for orthogonal functionality -- something like logging, for example.
You can add as many pre and post mixins as you like.
dogProto | mixinPreM (...) | ... | mixinM (...) | ... | factory
Or use the 'N' versions to provide an array:
dogProto | mixinPreNM ([a, b, c]) | mixinNM ([d, e, f]) | factory
Note the 'M' marker on the mixin functions. This is to make clear that these functions mutate the prototype object, which might be a bit surprising when using this style. We do not provide non-M versions of the mixin functions, because it's not obvious exactly what the semantics should be, as several alternatives could be equally intuitive.
Should the prototype chain be flattened? Should it be discarded, leaving only the own keys? Should it create a new object using and mutate it?
You can specify these behaviors explicitly:
dogProto | flattenPrototype | <mixin functions ...> |
dogProto | discardPrototype | <mixin functions ...> |
dogProto | Object.create | <mixin functions ...> |
You can consolidate a number of assignment statements into a single let expression, and also limit the scope of the assignments in a way which is easy to read. Code which is based on expressions rather than blocks of statements can be made referentially transparent, and therefore much easier to read, refactor, & prove the correctness of, especially considering that each statement is a possible side-effect inducing timebomb.
// --- convert a celsius value to both fahrenheit & kelvin.
const convertCelsius = (c) => letV (
c / 5 * 9 + 32, // fahrenheit
c - 273, // kelvin
(fah, kel) => [fah, kel],
)
letV
takes an arbitrary number of values, and expects the last one to be a
function. It simply passes the values in order to the function.
There is an 'N' form (letVN
, which takes an array of values and one
function).
Far more useful is lets
and letS
. (Think let\*
in racket).
If we went the other way, from Fahrenheit to Celsius & Kelvin:
// --- convert fahrenheit to celsius & kelvin
const convertFahrenheit = (f) => letV (
(f - 32) / 9 * 5, // celsius
(f - 32) / 9 * 5 + 273 // kelvin
(cel, kel) => [cel, kel],
)
We see that we are wasting work, but there is no way to capture that
intermediate expression to avoid calculating it again. With lets
, however,
we can:
// --- convert fahrenheit to celsius & kelvin
const convertFahrenheit = fah => lets (
_ => (fah - 32) / 9 * 5, // (1) celsius
(cel) => cel + 273, // (2) kelvin
(cel, kel) => [cel, kel], // (3) result
)
lets
expects each line to be a function. The first line is called with no
argument. The result (1) is passed as the argument to (2). The result of (1)
and the result of (2) are passed as the arguments to (3), and so on. The
result of the expression is the result of the last function.
(For now, there can be up to 6 lines. See below for a generic version).
And of course there is a stick version of lets
called letS
. Think of the
'S' marker as 'stick enabled' and the 's' as 'stick disabled'. letS
expects a value to be piped in. Note: the 'S' marker implies the 'N'
marker: the arguments must be an array, or else it would be impossible to
curry.
const convertFahrenheit = fah => fah | letS ([
(fah) => (fah - 32) / 9 * 5, // (1) celsius
(fah, cel) => cel + 273, // (2) kelvin
(fah, cel, kel) => [cel, kel] // (3) result
])
This wouldn't be the most natural use of letS
, but it shows how it works:
Function (1) receives as a single argument the piped in value (fah
in this case).
Function (2) receives fah
, and the result of (1). (3) receives fah
, the
results of (1) and (2), and so on.
By now we know that we can remove fah => fah |
from the first line to
make it point-free, and we can use underscores to indicate ignored values:
const convertFahrenheit = letS ([
(fah) => (fah - 32) / 9 * 5,
(_, cel) => cel + 273,
(_, cel, kel) => [cel, kel],
])
As an exercise you could try to make the entire expression as point-free as possible, at the expense of everyone's sanity:
import { letS, minus, divideBy, multiply, add, arg1, list, tail, } from 'stick-js'
const convertFahrenheit = letS ([
minus (32) >> divideBy (9) >> multiply (5),
arg1 >> add (273),
list >> tail,
])
convertFahrenheit (86) // [30, 303]
import { tryCatch, } from 'stick-js'
const dubiousFunction = ...
dubiousFunction | tryCatch (
// --- no exception: `v` is the return value of `dubiousFunction`
(v) => ...,
// --- exception thrown: `e` is the exception
(e) => e | decorateException ('Dubious function said:')
)
Sometimes it's nice to rethrow an exception, with a string prefixed to it so you can tell what went wrong:
(e) => e | decorateException ('Dubious function said:') | die
const throwError = reason => reason
| exception // new Error (reason)
| raise // throw it
const throwError = reason => reason | (exception >> raise)
// `exception >> raise` is also known as `die`
Note that this is illegal in JS, because throw
is not an expression:
const throwError = reason => throw new Error (reason)
But we can trick it like this:
const throwError = reason => reason | die
// or just
// const throwError = die
Now we can improve this common code:
let answer
try {
answer = dubiousFunction () + 10
} catch (e) {
console.warn (e)
answer = 'bad news'
}
Like this:
const answer = dubiousFunction | tryCatch (
plus (10),
(e) => {
e | decorateException ("That didn't go well")
| console.warn
return 'bad news'
},
}
Or perhaps:
const answer = dubiousFunction | tryCatch (
plus (10),
decorateException ("That didn't go well")
>> tap (console.warn)
>> ('bad news' | always)
)
import {
cond, condN, condS, guard, guardV, sprintf1, otherwise,
} from 'stick-js'
Naive form:
cond (
[3 === 4, _ => 'strange'],
[3 === 5, _ => 'even stranger'],
[null, _ => 'ok'],
)
An arbitrary number of lines can be provided.
With a stick idiom:
cond (
(_ => 3 === 4) | guard (_ => 'strange'),
(_ => 3 === 5) | guard (_ => 'even stranger'),
otherwise | guard (_ => 'ok'),
)
If the guard functions return simple expressions, guardV
can be more
convenient:
cond (
(_ => 3 === 4) | guardV ('strange'),
(_ => 3 === 5) | guardV ('even stranger'),
otherwise | guardV ('ok'),
)
The most useful version is condS
. Remember, 'S' implies 'N', so give it an
array.
const checkVal = val => val | condS ([
eq (4) | guard (val => val | sprintf1 ('%s was 4')),
lt (4) | guard (val => val | sprintf1 ('%s was less than 4')),
gt (4) | guard (val => val | sprintf1 ('%s was more than 4')),
otherwise | guardV ("error, this shouldn't happen"),
])
Cleaning it up a bit, and inverting the parenthetical test expression to use sticks:
const checkVal = condS ([
4 | eq | guard (sprintf1 ('%s was 4')),
4 | lt | guard (sprintf1 ('%s was less than 4')),
4 | gt | guard (sprintf1 ('%s was more than 4')),
otherwise | guardV ("error, this shouldn't happen"),
])
Wut?! This does work, strange as it looks. Try it for yourself:
; [3, 4, 5, {}]
| map (checkVal)
| join (' | ')
// 3 was less than 4 | 4 was 4 | 5 was more than 4 | error, this shouldn't happen
We provide regex functions which fit the idiom and mostly have an 'X' in the name (think /x if you know Perl).
These are 'extended regexes', in which whitespace is ignored. Note that we
do not skip comments in the regex, only whitespace, even inside character
classes. Use \s
if you really want to match on whitespace.
'egbert' | xMatch (/ (eg) (..) [rs] /)
// [ 'egber', 'eg', 'be', index: 0, input: 'egbert' ]
// --- same, using a regex string instead of a RegExp literal.
'egbert' | xMatchStr (' (eg) (..) [rs] ')
// [ 'egber', 'eg', 'be', index: 0, input: 'egbert' ]
const vowels = []
const mapper = appendToM (vowels)
'egbert druppelvanger' | xMatchGlobal (/ [ae] /) (mapper)
vowels // [ 'e', 'e', 'e', 'a', 'e' ]
'egbert\ndruppelvanger' | xMatchStrFlags (' ^ d ') ('s')
// null
'egbert\ndruppelvanger' | xMatchStrFlags (' ^ d ') ('m')
// [ 'd', index: 7, input: 'egbert\ndruppelvanger' ]
const toUpper = dot ('toUpperCase')
const ifReplaceVowels = ifXReplace (/ ([aeiou]) /) ('x')
'egbert' | ifReplaceVowels (toUpper) ('bad' | always)
// XGBXRT
const ifReplaceVowelsGlobal = ifXReplace (/ ([aeiou]) /g) ('x')
'egbert' | ifReplaceVowelsGlobal (toUpper) ('bad' | always)
// XGBXRT
// --- same, using a regex string instead of a RegExp literal.
const ifReplaceVowelsGlobalAlt = ifXReplaceStrFlags (' ([aeiou]) ') ('g') ('x')
'egbert' | ifReplaceVowelsGlobalAlt (toUpper) ('bad' | always)
// XGBXRT
If you're like the author you have a hard time remembering how Ramda's
all
, any
, both
, either
, and
, or
, anyPass
, and so on work. Does
the 'all' refer to all the functions? or all the values? and so on.
Our solution to making the semantics clearer and enriching the functionality of these functions centers around the preposition 'against': you match a value against a predicate.
const isOdd = x => isInteger (x) && (x % 2 !== 0)
const isLt3 = 3 | lt
// --- return `true` if input is truthy, `false` otherwise.
const truthy = id
// const truthy = Boolean // also works
Match all values against the predicate isOdd
; [1, 2, 3, 4, 5] | allAgainst (isOdd) // false
; [1, 3, 5] | allAgainst (isOdd) // true
Match all values against the predicate truthy
const allTruthy = allAgainst (truthy)
; [1, 2, 3, 4, 5, null] | allTruthy // false
; [1, 2, 3, 4, 5] | allTruthy // 5
The value matches all the predicates
const isOddAndLt3 = againstAll ([isOdd, isLt3])
1 | isOddAndLt3 // true
1.1 | isOddAndLt3 // false
2 | isOddAndLt3 // false
3 | isOddAndLt3 // false
The value matches any of the predicates
const isOddOrLt3 = againstAny ([isOdd, isLt3])
2 | isOddOrLt3 // true
3 | isOddOrLt3 // true
4 | isOddOrLt3 // false
5 | isOddOrLt3 // true
We can also match multiple values against multiple predicates, in various combinations of 'all' and 'any' (Ramda doesn't have this out of the box -- corrections welcome)
All the values are odd and less than 3.
const allOddAndLt3 = allAgainst (isOddAndLt3)
; [1, 2, 3, 4, 5] | allOddAndLt3 // false
; [1, 3, 5] | allOddAndLt3 // true
All the values are odd and less than 3.
const allOddOrLt3 = allAgainst (isOddOrLt3)
; [1, 2, 3, 4, 5] | allOddOrLt3 // false
; [2, 3, 5] | allOddOrLt3 // true
Any of the vales are odd and less than 3.
const anyOddAndLt3 = anyAgainst (isOddAndLt3)
; [3, 4, 5] | anyOddAndLt3 // false
; [2, 4, 5] | anyOddAndLt3 // false
; [1, 4, 5] | anyOddAndLt3 // true
Any of the vales are odd or less than 3.
const anyOddOrLt3 = anyAgainst (isOddOrLt3)
; [4, 6] | anyOddOrLt3 // false
; [3, 6] | anyOddOrLt3 // true
; [3, 5] | anyOddOrLt3 // true
; [2, 6] | anyOddOrLt3 // true
; [1, 6] | anyOddOrLt3 // true
Both values are truthy / either value is odd. Note that these forms take
spread out arguments, not an array (so they are sugar for allAgainst
/
anyAgainst
)
const bothTruthy = bothAgainst (truthy)
const eitherOdd = eitherAgainst (isOdd)
const isOddAndLt3Alt = againstBoth (isOdd) (isLt3)
const isOddOrLt3Alt = againstEither (isOdd) (isLt3)
// --- i.e. ; [null, 3] | allTruthy
bothTruthy (null, 3) // false
bothTruthy (1, 3) // 3
eitherOdd (1, 2) // true
eitherOdd (null, 2) // false
eitherOdd (2, 4) // false
1 | isOddAndLt3Alt // true
1.1 | isOddAndLt3Alt // false
2 | isOddAndLt3Alt // false
3 | isOddAndLt3Alt // false
2 | isOddOrLt3Alt // true
3 | isOddOrLt3Alt // true
4 | isOddOrLt3Alt // false
5 | isOddOrLt3Alt // true
We provide 8 basic merge functions, corresponding to all combinations of three binary choices:
There are a few conventions to keep in mind when trying to understand the semantics. To vs. from is just a question of switching the arguments, so we don't need to discuss it, but the other 4 combinations have some caveats.
tgt | merge (src) // (1) own, immutable
tgt | mergeIn (src) // (2) in, immutable
tgt | mergeM (src) // (3) own, mutable
tgt | mergeInM (src) // (4) in, mutable
// mergeTo, mergeInTo, mergeToM, mergeInToM: 'to' forms
In the immutable cases, a shallow clone is made of the target before merging. You must keep in mind whether the clone will use only 'own' properties or also the prototype ('in') properties. Case (1) corresponds to 'own' and case (2) to 'in'.
No matter which it is, all copied properties will become own properties of the clone.*
Then, properties are copied over from the source: only own properties in case (1), also 'in' properties in case (2).
The rule to remember in the immutable case is: 'own' merges with 'own' and 'in' with 'in'.
In the mutable case, the target object is not cloned nor altered in any way, except of course that properties are copied in from the source. In particular this means that the 'own' in case (3) only applies to the source: the prototype chain of the target will not be flattened or discarded or altered at all.
The rule to remember in the mutable case is: the target is never altered in any way, besides having properties copied in. So the 'own' / 'in' distinction only applies to the source.
We feel that these conventions are the most straightforward and lead to easily inferrable behavior.
In all cases, we are only ever talking about enumerable properties.
* This is good enough for most styles of functional programming in JS, many
of which don't even bother with the distinction. People often expect
shallow, cheap objects when programming this way. If you absolutely must
preserve the prototype chain intact, you'll have to find a way to clone it
yourself, then use the 'M' versions of our merge functions on your cloned
object. You might also get away with using Object.create
on it first,
which will of course create one more link in the prototype chain.
import { path, prop, whenTrue, always, } from 'stick-js'
If you use react/redux, perhaps with saga, chances are your modules end in something like this:
const withConnect = connect(mapStateToProps, mapDispatchToProps);
const withReducer = injectReducer({ key: 'home', reducer });
const withSaga = injectSaga({ key: 'home', saga });
export default compose(
withReducer,
withSaga,
withConnect,
)(HomePage);
We should see by now that this composing of functions, invoked upon a single value, is exactly our pipe pattern. So why not:
export default HomePage
| connect (mapStateToProps, mapDispatchToProps)
| injectSaga ({ key: 'home', saga, })
| injectReducer ({ key: 'home', reducer, })
And maybe you call actions using a structure like:
export function mapDispatchToProps(dispatch) {
return {
onChangeUsername: (evt) => dispatch(changeUsername(evt.target.value)),
};
};
Why not:
export const mapDispatchToProps = (dispatch) => ({
onChangeUsername: path (['target', 'value'] >> changeUsername >> dispatch,
})
Try it yourself and see :D
If you use styled components
, perhaps you pass optional props in. Checking
for the presence of the props can be annoying, so how about:
const SomeElementS = styled.div`
top: 5%;
left: 5%;
${ prop ('width') >> whenOk (sprintf1 ('width: %spx;')) }
${ prop ('height') >> whenOk (sprintf1 ('height: %spx;')) }
${ prop ('error') >> whenTrue ('color: red;' | always) }
`
<SomeElementS width='100%' error={true} />
If you use saga
, perhaps you have something like this:
export function* getRepos() {
const username = yield select(makeSelectUsername());
const requestURL = `https://api.github.com/users/${username}/repos`;
try {
const repos = yield call(request, requestURL);
yield put(reposLoaded(repos, username));
} catch (err) {
yield put(repoLoadingError(err));
}
}
How about this:
export function* getRepos () {
const username = yield makeSelectUsername () | select
const requestURL = username | sprintf1 ('https://api.github.com/users/%s/repos')
try {
const repos = yield call (request, requestURL)
reposLoaded (repos, username) | reposLoaded | put
} catch (err) {
yield err | repoLoadingError | put
}
}
Note that we can't use our tryCatch
function here, because of the yield
in the catch
clause.
If you use reselect
, this is fine:
const selectHome = (state) => state.get('home');
const makeSelectUsername = () => createSelector(
selectHome,
(homeState) => homeState.get('username')
);
But how about this:
const get = dot1 ('get')
const selectHome = get ('home')
const makeSelectUsername = () => createSelector (
selectHome,
get ('username'),
)
When composing selectors, something like this works nicely to make sure the one being composed is valid:
export const makeSelectBooks = _ => createSelector (
selectHome,
get ('books'),
)
export const makeSelectBookTitles = _ => createSelector (
makeSelectBooks (),
'titles' | get | whenOk,
)
The author uses stick idioms to slay a common front-end pattern. When you're
fetching your list of todos, the list should be undefined
when it hasn't
been set yet, and empty only if it has been fetched and really is empty.
This makes testing easier, avoids weird flickers, lets you show a spinner,
etc. It does introduce an extra condition you need to test for in your code,
but we can handle this nicely:
const ListS = styled.div`
min-height: 150px;
`
const List = ({ children }) => <ListS>
{children | ifOk (identity) (spinner)}
</ListS>
When you're using a framework like Express, you have the well-known app
object that you carry around everywhere. It just so happens that nearly all
methods of app
return this
, so that chaining works in the familiar way:
app
.use (...)
.all (...)
.post ('/endpoint1', ((req, res) => ...))
.patch ('/endpoint2', ((req, res) => ...))
.get ('/endpoint3', ((req, res) => ...))
...
.listen (config.port, ...)
But there are cases when the makers were not so thoughtful, or when you simply don't know (or don't care) what a function or method returns. The pipe will free you from the limitations of the dot, and allow you to compose your own fluid interfaces. We'll use Express here to prove that it works. See the raindrops example for how you might use this with WebGL, and there are many other places this can be used.
import { side1, side2, list, appendTo, } from 'stick-js'
import { fromPairs, } from 'ramda'
const get = side2 ('get')
const post = side2 ('post')
const patch = side2 ('patch')
const use = side1 ('use')
const all = side2 ('all')
const send = side1 ('send')
const status = side1 ('status')
const listen = side2 ('listen')
const sendJSON = side1 ('json')
const sendStatus = code => data => status (code) >> sendJSON (data)
const msg = appendTo (['msg']) >> list >> fromPairs
app | use (bodyParser.json())
| all ('*', (req, res, next) => {
...
next ()
})
| post ('/endpoint1', ((req, res) => {
...
res | sendStatus (500) ('Server error' | msg)
}))
| patch ('/endpoint2', ((req, res) => {
...
res | sendStatus (200) ({ results, })
}))
...
| get ('/endpoint3', ((req, res) => ...))
| listen (config.port) (...)
Maybe
null
and undefined
for a while)Here is an example showing how you can deal with failure paths, using
Maybe
from
bilby by @puffnfresh. In this toy
example, we start with a French word, then:
look up a translation (mocked in a table);
failure path: the translation might not exist (or the network is down, a mouse ate through the cable, etc.)
look up a corresponding 'count' value (also mocked in a table);
failure path: the count might not exist
divide this number into 10 for some reason;
failure path: the number might be 0
import { some as Just, none as Nothing, } from 'bilby'
const toMaybe = o => o | ifOk (
Just,
Nothing | always,
)
const flatMap = dot1 ('flatMap')
const fold = dot2 ('fold')
const translations = {
rouge: 'red',
bleu: 'blue',
vert: 'green',
// blanc missing
}
const count = {
red: 5,
blue: 0,
// green missing
}
const formatAnswer = input => answer => [input | yellow, answer] | sprintfN ('%s → %s')
const go = _ =>
['rouge', 'bleu', 'vert', 'blanc']
| map (doit)
| tap (map (log))
const doit = x => x | calculate | formatAnswer (x)
const calculate = french => doLookup (french)
| fold (
// --- Just (answer)
answer => answer + ' ' + green ('✔'),
// --- Nothing.
red ('✘') | always,
)
const doLookup = french => french
| getTranslation
| flatMap (getCount)
| flatMap (getQuotient)
const getTranslation = french => translations [french] | toMaybe
const getCount = english => count [english] | toMaybe
const getQuotient = condS ([
0 | eq | guard (_ => Nothing),
otherwise | guard (cnt => Just (10 / cnt)),
])
go ()
The above example, using bilby
's Either
instead of Maybe
, and a more
point-free style.
The advantage of Either
is that in addition to flatMap
taking care of
the failure path, you can also see why it failed. By convention the 'Left'
branch is considered a failure, and a string stored in 'Left' represents the
reason.
import { left as Left, right as Right, } from 'bilby'
const toEither = l => ifOk (
Right,
l | Left | always,
)
const flatMap = dot1 ('flatMap')
const fold = dot2 ('fold')
const arrowSnd = f => ([a, b]) => [a, b | f]
const foldArrow = f => ([a, b]) => f (a, b)
const translations = {
rouge: 'red',
bleu: 'blue',
vert: 'green',
// blanc missing
}
const count = {
red: 5,
blue: 0,
// green missing
}
const formatAnswer = asterisk2 (yellow, id) >> sprintfN ('%s → %s')
const getTranslation = propOf (translations) >> toEither ('no translation')
const getCount = propOf (count) >> toEither ('no count')
const getQuotient = condS ([
0 | eq | guardV ('count was zero' | Left),
otherwise | guard (divideInto (10) >> Right),
])
const doLookup = getTranslation
>> flatMap (getCount)
>> flatMap (getQuotient)
const calculate = doLookup >> fold (
// --- Left (failureReason)
prependTo (['✘' | red]) >> sprintfN ('%s %s'),
// --- Right (answer)
prependTo (['✔' | green]) >> sprintfN ('%s %s'),
)
const doit = timesV (2)
>> arrowSnd (calculate)
>> foldArrow (formatAnswer)
const go = _ =>
['rouge', 'bleu', 'vert', 'blanc']
| map (doit)
| tap (map (log))
go ()
Abstract (or 'algebraic') data types can help eliminate an entire class of bugs, by making impossible states unrepresentable.
Imagine you have something like a traffic light, which at any moment can be either red, yellow, green, or broken. (Or a download, which can be in progress, stopped, completed, failed; or an API call, etc.)
You can use a normal object to represent these sorts of things, which JS
programmers do all the time of course. The problem is that as the problem
domain becomes more complex, it gets increasingly harder to verify the
correctness of such a so-called 'product type'. You will probably find
yourself carrying around properties like 'error' and 'state' and 'type' and
so on using a lot of if
statements to check for illegal states.
Another way is to model the data using ADTs, build the states, then branch using a 'catamorphism' to resolve the states when you're ready.
In this example we use daggy by @fantasyland to create an ADT representing various kinds of numerical sequences.
In Haskell our declaration would be:
data Sequence = ArithmeticSequence Int -- y = nx
| GeometricSequence Int -- y = c ** x
| IrregularSequence
| ErrorSequence String -- error with a reason
In (pseudo-)Java maybe something like:
abstract class Sequence {}
class ArithmeticSequence extends Sequence {
public ArithmeticSequence(int n) {} // y = nx
}
class GeometricSequence extends Sequence {
public GeometricSequence(int c) {} // y = c ** x
}
class IrregularSequence extends Sequence {
public IrregularSequence() {}
}
class ErrorSequence extends Sequence {
public ErrorSequence(String reason) {}
}
Using stick idioms and daggy
:
// --- types.js
import daggy from 'daggy'
export const Sequence = daggy.taggedSum ('Sequence', {
ArithmeticSequence: ['n'],
GeometricSequence: ['c'],
IrregularSequence: [],
ErrorSequence: ['reason'],
})
const { ArithmeticSequence, GeometricSequence, IrregularSequence, ErrorSequence, } = Sequence
export { ArithmeticSequence, GeometricSequence, IrregularSequence, ErrorSequence, }
// --- sequence.js
const testReduce = f => n => (acc, x) => f (acc, x) === n ? x : null
const testReduceArithmetic = minus | testReduce
const testReduceGeometric = divideBy | testReduce
const testSequence = g => f => ([a, b, ...rest]) => lets (
_ => b | g (a),
n => rest | reduceAbort (n | f) (b) (null),
(n, reduced) => reduced === null ? false : n,
)
const containsNull = null | contains
export const isArithmetic = testReduceArithmetic | testSequence (minus)
export const isGeometric = testReduceGeometric | testSequence (divideBy)
export const isError = x => containsNull (x) ? 'contains null' : false
// --- util.js
export const cata = dot1 ('cata')
export const repeatChar = n => timesV (n) >> join ('')
export const pad = n => str => (n - str.length) | condS ([
0 | gt | guard (pad => [str, ' ' | repeatChar (pad)] | join ('')),
otherwise | guardV (str),
])
// --- index.js
import { ArithmeticSequence, GeometricSequence, IrregularSequence, ErrorSequence, } from './types'
import { isArithmetic, isGeometric, isError, } from './sequence'
import { cata, repeatChar, pad, } from './util'
const checkSequence = condS ([
isArithmetic | guard ((_, n) => n | ArithmeticSequence),
isGeometric | guard ((_, c) => c | GeometricSequence),
containsNull | guard (() => 'contains null' | ErrorSequence),
otherwise | guard (() => IrregularSequence),
])
const format = cata ({
ArithmeticSequence: n => ['arithmetic', n] | map (yellow) | sprintfN ('%s: y = %sx'),
GeometricSequence: c => ['geometric', c] | map (green) | sprintfN ('%s: y = %s ** x'),
ErrorSequence: reason => reason | red | sprintf1 ('error: %s'),
IrregularSequence: _ => 'irregular sequence' | brightRed,
})
const repeatChar = n => timesV (n) >> join ('')
const pad = n => str => (n - str.length) | condS ([
0 | gt | guard (pad => [str, ' ' | repeatChar (pad)] | join ('')),
otherwise | guardV (str),
])
const report = xs => resolved =>
[xs | join (', ') | pad (13), resolved]
| sprintfN ('%s → %s')
const doit = xs => xs
| checkSequence
| format
| report (xs)
const go = _ =>
[
[0, 4, 8, 12], // --- arithmetic
[1, 3, 9, 27], // --- geometric
[0, 1, 2, 5], // --- irregular
[null, 1, 2, 5] // --- error
]
| map (doit)
| tap (map (log))
go ()
We had an isInteger
function above as:
const { floor, } = Math
const isInteger = x => x
| floor
| eq (x)
If a number equals its own floor, it's an integer.
For a challenge you could try to make this point-free. The difficult part is
wresting the x
free out of the 3rd line.
We can use the concept of 'arrows', though in a far less rigorous form than people might be used to.
First spread the first line x
into an array [x, x]
x | timesV (2) // [x, x]
Now use the asteriskN
function, which works by taking an array of values
and an array of functions, lining them up, and applying the functions to the
corresponding value.
So we can do an asterisk of [x, x]
with [id, floor]
, where id
is the identity function.
[id, floor]
↓ ↓
[x, x ]
and get [id (x), floor (x)]
, or [x, floor (x)]
Now look at the passToN
function:
; [a, b, ...] | passToN (f)
yields f (a, b, ...)
If we take our result and pipe it to passToN (eq)
, we get:
; [x, floor (x)]
| passToN (eq)
which is
eq (x, floor (x))
which is true if & only if x === floor (x)
, in other words, if &
only if x is an integer.
Putting it together:
const isInteger = x => x
| timesV (2)
| asteriskN ([id, floor])
| passToN (eq)
Applying the reduction a | b | c → a | (b >> c)
const isInteger = x => x
| (timesV (2) >> asteriskN ([id, floor]))
| passToN (eq)
And that long line is useful enough to merit its own function, which takes a
function (in our case floor
) to apply to a value in second position. We'll
call it arrowSnd
:
const arrowSnd = f => timesV (2) >> asteriskN ([id, f])
And stick it back in:
const isInteger = x => x
| arrowSnd (floor)
| passToN (eq)
And make it point-free:
const isInteger = arrowSnd (floor) >> passToN (eq)
Your turn :D
(Based on a conversation with @puffnfresh).
Let us consider the >>
operator (though you can use <<
if you prefer),
and ask:
()
syntax (and not requiring something like .call()
)We explore 3 ways of doing this.
stick provides the functions composeAsMethods
and composeAsMethodsRight
.
By changing the header to:
defineBinaryOperator ('>>', (...args) => composeAsMethodsRight (...args))
defineBinaryOperator ('<<', (...args) => composeAsMethods (...args))
Then a >> b
will desugar to b.compose (a)
, instead of to compose (b,
a)
as we have been doing.
Is is then up to you to ensure that b
has a method called .compose
. b
could be a custom object, or it can be a function, keeping in mind that
functions are also objects whose prototype is called Function.prototype.
Solutions 1) and 2) use this technique.
Solution 3) is to keep desugaring it as we have been until now.
In 1), b
is an object with a method compose
. It will be the result of
Object.create
on a 'kleisli prototype' object. We must also add compose
to Function.prototype
so that the ordinary compositions work.
In 2), b
is a function, and we must again splice compose
into
Function.prototype
.
In all 3 of these cases we need a way to prepare functions so that the
correct .compose
call is used (cases 1 and 2), or so that compose
works
as it should (case 3). We will use a function called k
to enhance a
normally composing function (f
) into a Kleisli-composing one (k (f)
).
We'll start with some (x)
where x
is an integer, (using bilby.some
),
and pass it through step1
Kleisli-composed with step2
.
// --- some (x+1) if x>=0, else none.
const step1 = ifLt0 (none | always, inc >> some)
// --- some (x+1) if x is even, else none.
const step2 = ifOdd (none | always, inc >> some)
Here are the results of some experiments.
All examples result in ['none', 'none', 3, 'none']
.
See the source for the implementations, omitted here.
1a) Requires id
at the beginning of the chain -- not nice.
const transform = id >> k (step1) >> k (step2)
; -1 | rangeTo (3)
| map (some >> transform >> getOrElse ('none'))
1b) We can get rid of id
, but we have to put the some
into the chain.
const transform = some
>> k (step1)
>> k (step2)
; -1 | rangeTo (3)
| map (transform >> getOrElse ('none'))
1c) We can get rid of id
, and put some
back where we like it, but the
chain requires an extra k
around the whole thing.
const transform = k (step1 >> k (step2))
; -1 | rangeTo (3)
| map (some >> transform >> getOrElse ('none'))
2a-c) All the same possibilities.
2d) Finally, the first form which we consider usable:
const transform = k (step1) >> k (step2)
; -1 | rangeTo (3)
| map (some >> transform >> getOrElse ('none'))
2) is perhaps the least interesting of the three, because .compose
doesn't
even get called in the case of the k()
functions. But it does lead us to
version 3:
Version 3) is the simplest of all and doesn't require patching any prototypes. It allows us to replicate the form from 2d) using precisely the idiom we've been using all along.
We simply define k
as dot1 ('flatMap')
, and desugar a >> b
as compose
(b, a)
as before:
const k = dot1 ('flatMap')
const transform = k (step1) >> k (step2)
; -1 | rangeTo (3)
| map (some >> transform >> getOrElse ('none'))
// ['none', 'none', 3, 'none']
// QED
Stick is fast. (@todo link benchmark)
Though it initially depended on Ramda, we have decided to eliminate that
dependency by reimplementing many of the functions. While profiling the
WebGL example we found that even trivial functions like R.flip
and R.tap
are surprisingly expensive.
This really only becomes an issue in critical loops with millions of iterations per second.
It is true that a | b
compiles to three function calls, whereas b (a)
is
only one. But this is almost certainly not going to affect your app. Your JS
runtime can call a lot of functions per millisecond.
Nonetheless you are encouraged to mix and match our functions with whichever functional libraries you like -- Ramda, Lodash/FP, or anything else, as it suits you.
import { map, } from 'ramda'
import { filter, } from 'lodash/fp'
import { ifPredicate, } from 'stick-js'
The stick idiom will still work, as long as the functions are curried and data-last.
Furthermore Ramda is probably perfectly fine for your app, and its functions
often provide type-checking and error messages (we don't), and many of their
functions are more sophisticated. R.map
works on functors and
transformers, for example -- ours doesn't.
And, it is our belief that if you are already using the flow
pattern in
Lodash/FP or the pipe
function in Ramda, that it will really be a
no-brainer to overload the operator and keep everything else the same.
_.flow (
_.split (' '),
_.map (capitaliseFirstLetter),
_.join (' '),
) (myData)
// ->
myData
| _.split (' '),
| _.map (capitaliseFirstLetter),
| _.join (' ')
The curried functions you import from the main module are written first using manual currying, and then recurried and exported. This is in order to allow both calling styles.
If you are squeezing performance out of a loop -- in an animation, a particle system, WebGL, a server -- you can check the docs to see if your function is exported by 'stick-js/manual'. If so, you can directly import the manual version, but you must remember to call it using the manual style:
import { merge, } from 'stick-js/manual'
merge (obj1, obj2) // will not work
obj2 | merge (obj1) // ok
merge (obj1) (obj2) // also ok
lets
Here is a generic form of lets
which takes any number of non-zero
arguments. We removed it from stick because it depends on mapAccum
, for
which we do not currently have an implementation without depending on Ramda.
// --- generic form, for any non-zero number of arguments.
const lets = (() => {
const executeStep = prevVals => applyToN (prevVals)
return (...xs) => xs
// --- acc contains running output array, up to the previous item.
| mapAccum ((acc, v) => executeStep (acc) (v)
| (stepVal => [[...acc, stepVal], stepVal])
) ([])
| prop (1)
| last
}) ()
This is not fast, but it is correct. You can prove it with a contrived
fibonacci example. We'll model fibonacci (n)
as
lets (
_ => 1,
_ => 1,
(a, b) => a + b,
(_, b, c) => b + c,
...
(a, b, ...) => [a, b, ...],
)
import { list, timesV, applyToN, rangeTo, } from 'stick-js'
const fibonacci = (n) => {
const sumLastTwo = (xs) => {
const l = xs.length
return xs [l-1] + xs [l-2]
}
const entry = (...prev) => {
const l = prev.length
return l === 0 ? 1 :
l === 1 ? 1 : sumLastTwo (prev)
}
const refs = entry | timesV (n + 1)
return lets (...refs, list)
}
1 | rangeTo (20)
| map (fibonacci)
/*
[ [ 1, 1 ],
[ 1, 1, 2 ],
[ 1, 1, 2, 3 ],
[ 1, 1, 2, 3, 5 ],
[ 1, 1, 2, 3, 5, 8 ],
[ 1, 1, 2, 3, 5, 8, 13 ],
[ 1, 1, 2, 3, 5, 8, 13, 21 ],
[ 1, 1, 2, 3, 5, 8, 13, 21, 34 ],
[ 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 ]
...
]
*/
Of course, we've saved your precious bitwise operators. You can either:
Use the functional form
import { bitwiseOr, bitwiseShiftBy, } from 'stick-js'
4 | bitwiseOr (9) // 13
Do your bitwise math in a separate scope than that in which the
defineBinaryOperator
calls appear. The operators are only overloaded in
the scope in which the calls are made. We recommend doing the bitwise math
in a separate source file and not mixing the two styles in one file.


bycatch management species data dynamic habitat California risk ocean fishing leatherback marine fisheries sea catch {border-style high px;} #ffffff;} low pixels approaches predictions blue daily Fig. area Hazen approach fishery integrated static target EcoCast available closures protected spatial tracking using variability August Bograd http://orcid.org/--- lions models new support surface turtle turtles Crowder PLCA Science [], areas climate closure compared fig. multiple observer suitability swordfish Costa Dynamic Pacific S). distribution fisheries. model multispecies px; representing sharks significant used weightings {font-family Current Ecol. Lewison Maxwell ecological environmental existing font-size relative risk. seasonal tool Bailey Benson December Foley Hobday LINK Mar. based double; economic focal including leatherbacks mesoscale near predictive real-time reduce season species, study sustainable threshold time turtles, warm year Briscoe Leatherback Supplementary border-color border-width conservation create current effort important influence modeling movie nontarget oceanographic patterns pelagic predators predicted provide rates reduction resolution scales season, solid; species. suitable temporal track use values waters {font-style {font-weight Animation Blue Conserv. Dewar Dunn E.L.H. Eguchi Fisheries Forney Moore NOAA’s Nat. Nature Oceanogr. PLCA. SSHa Scales Sci. Sea Shaffer Species Worm address anomalously bold boosted change. climate-ready closed conditions conservative courier; days designed distributed eco-informatics efficacy efficiency em; endangered gillnet greater highlight impacts interannual managers mean mitigation opportunity persistence predicting product protecting protection pt;} red regression required result resulting results sets shark single space temperature upwelling


Chasm Ain't ScoreMaster
This wizard will establish the basic characteristics of the rally. You will be able to update them later on, this is just intended to get the process off the ground for now.
This wizard will establish the basic characteristics of the rally. You will be able to update them later on, this is just intended to get the process off the ground for now.


| 1 |
Tang_2015 |
Optimization of antigen dose for a receptor-binding domain-based subunit vaccine against MERS coronavirus |
Tang, Jian; Zhang, Naru; Tao, Xinrong; Zhao, Guangyu; Guo, Yan; Tseng, Chien-Te K; Jiang, Shibo; Du, Lanying; Zhou, Yusen |
2015 |
2015-04-15 |
PMC |
N |
PMC4514392 |
25874632.0 |
10.1080/21645515.2015.1021527 |
ykzsoafe |
0.862232 |
|
|
| 2 |
Wang_2019 |
Combining a Fusion Inhibitory Peptide Targeting the MERS-CoV S2 Protein HR1 Domain and a Neutralizing Antibody Specific for the S1 Protein Receptor-Binding Domain (RBD) Showed Potent Synergism against Pseudotyped MERS-CoV with or without Mutations in RBD |
Wang, Cong; Hua, Chen; Xia, Shuai; Li, Weihua; Lu, Lu; Jiang, Shibo |
2019 |
2019-01-06 |
COMM-USE |
N |
PMC6356712 |
30621343.0 |
10.3390/v11010031 |
pgxxkfc0 |
0.761698 |
|
Xia_S_2019 |
| 3 |
Wang_2019 |
Engineering a Novel Antibody-Peptide Bispecific Fusion Protein Against MERS-CoV |
Wang, Lili; Xu, Jiyan; Kong, Yu; Liang, Ruiying; Li, Wei; Li, Jinyao; Lu, Jun; Dimitrov, Dimiter S.; Yu, Fei; Wu, Yanling; Ying, Tianlei |
2019 |
2019-11-04 |
COMM-USE |
Y |
PMC6963733 |
31690009.0 |
10.3390/antib8040053 |
7dckgg6b |
0.747116 |
|
|
| 4 |
Al-amri_2017 |
Immunogenicity of Candidate MERS-CoV DNA Vaccines Based on the Spike Protein |
Al-amri, Sawsan S.; Abbas, Ayman T.; Siddiq, Loai A.; Alghamdi, Abrar; Sanki, Mohammad A.; Al-Muhanna, Muhanna K.; Alhabbab, Rowa Y.; Azhar, Esam I.; Li, Xuguang; Hashem, Anwar M. |
2017 |
2017-03-23 |
COMM-USE |
N |
PMC5362948 |
28332568.0 |
10.1038/srep44875 |
wp6yklrx |
0.695857 |
|
|
| 5 |
Ma_C_2014 |
Intranasal vaccination with recombinant receptor-binding domain of MERS-CoV spike protein induces much stronger local mucosal immune responses than subcutaneous immunization: Implication for designing novel mucosal MERS vaccines |
Ma, Cuiqing; Li, Ye; Wang, Lili; Zhao, Guangyu; Tao, Xinrong; Tseng, Chien-Te K.; Zhou, Yusen; Du, Lanying; Jiang, Shibo |
2014 |
2014-04-11 |
None |
N |
PMC4194189 |
24560617.0 |
10.1016/j.vaccine.2014.02.004 |
wnrsas0k |
0.684957 |
|
Tang_2015 |
| 6 |
Tai_W_2016 |
A recombinant receptor-binding domain of MERS-CoV in trimeric form protects human dipeptidyl peptidase 4 (hDPP4) transgenic mice from MERS-CoV infection |
Tai, Wanbo; Zhao, Guangyu; Sun, Shihun; Guo, Yan; Wang, Yufei; Tao, Xinrong; Tseng, Chien-Te K.; Li, Fang; Jiang, Shibo; Du, Lanying,; Zhou, Yusen |
2016 |
2016-12-31 |
PMC |
N |
PMC5167628 |
27750111.0 |
10.1016/j.virol.2016.10.005 |
2071v9fu |
0.649048 |
|
|
| 7 |
He_L_2019 |
Enhanced Ability of Oligomeric Nanobodies Targeting MERS Coronavirus Receptor-Binding Domain |
He, Lei; Tai, Wanbo; Li, Jiangfan; Chen, Yuehong; Gao, Yaning; Li, Junfeng; Sun, Shihui; Zhou, Yusen; Du, Lanying; Zhao, Guangyu |
2019 |
2019-02-19 |
COMM-USE |
N |
PMC6410414 |
30791410.0 |
10.3390/v11020166 |
jsszmnm0 |
0.625911 |
|
|
| 8 |
Kim_Y_2019 |
Selection and Characterization of Monoclonal Antibodies Targeting Middle East Respiratory Syndrome Coronavirus through a Human Synthetic Fab Phage Display Library Panning |
Kim, Yoonji; Lee, Hansaem; Park, Keunwan; Park, Sora; Lim, Ju-Hyeon; So, Min Kyung; Woo, Hye-Min; Ko, Hyemin; Lee, Jeong-Min; Lim, Sun Hee; Ko, Byoung Joon; Park, Yeon-Su; Choi, So-Young; Song, Du Hyun; Lee, Joo-Yeon; Kim, Sung Soon; Kim, Dae Young |
2019 |
2019-07-31 |
COMM-USE |
N |
PMC6783954 |
31544848.0 |
10.3390/antib8030042 |
1zcxw6yu |
0.617959 |
|
Lau_S_2020 |
| 9 |
Han_H_2018 |
Neutralizing Monoclonal Antibodies as Promising Therapeutics against Middle East Respiratory Syndrome Coronavirus Infection |
Han, Hui-Ju; Liu, Jian-Wei; Yu, Hao; Yu, Xue-Jie |
2018 |
2018-11-30 |
COMM-USE |
N |
PMC6315345 |
30513619.0 |
10.3390/v10120680 |
698voi9y |
0.612783 |
|
Xu_J_2019 |
| 10 |
Zhang_2014 |
Current advancements and potential strategies in the development of MERS-CoV vaccines |
Zhang, Naru; Jiang, Shibo; Du, Lanying |
2014 |
2014-04-26 |
None |
Y |
PMC4241375 |
24766432.0 |
10.1586/14760584.2014.912134 |
strhszpd |
0.609001 |
|
|
| 11 |
Wang_2019 |
A novel luciferase immunosorbent assay performs better than a commercial enzyme-linked immunosorbent assay to detect MERS-CoV specific IgG in humans and animals |
Wang, Wenling; Wang, Tianyu; Deng, Yao; Niu, Peihua; A, Ruhan; Zhao, Jincun; Peiris, Malik; Tang, Shixing; Tan, Wenjie |
2019 |
2019-12-31 |
PMC |
N |
PMC7148641 |
|
10.1016/j.bsheal.2019.12.006 |
lmzhm0os |
0.595977 |
|
|
| 12 |
Zhang_2015 |
Receptor-binding domain-based subunit vaccines against MERS-CoV |
Zhang, Naru; Tang, Jian; Lu, Lu; Jiang, Shibo; Du, Lanying |
2015 |
2015-04-16 |
None |
N |
PMC4439384 |
25445336.0 |
10.1016/j.virusres.2014.11.013 |
g9jsnug4 |
0.586865 |
|
Tang_2015 |
| 13 |
Xia_S_2014 |
Middle East respiratory syndrome coronavirus (MERS-CoV) entry inhibitors targeting spike protein |
Xia, Shuai; Liu, Qi; Wang, Qian; Sun, Zhiwu; Su, Shan; Du, Lanying; Ying, Tianlei; Lu, Lu; Jiang, Shibo |
2014 |
2014-12-19 |
PMC |
N |
PMC7114414 |
25451066.0 |
10.1016/j.virusres.2014.10.007 |
7hwscr6i |
0.540397 |
|
|
| 14 |
Xia_S_2019 |
Potent MERS-CoV Fusion Inhibitory Peptides Identified from HR2 Domain in Spike Protein of Bat Coronavirus HKU4 |
Xia, Shuai; Lan, Qiaoshuai; Pu, Jing; Wang, Cong; Liu, Zezhong; Xu, Wei; Wang, Qian; Liu, Huan; Jiang, Shibo; Lu, Lu |
2019 |
2019-01-14 |
COMM-USE |
N |
PMC6357153 |
30646495.0 |
10.3390/v11010056 |
2mamwrfq |
0.526481 |
|
|
| 15 |
Agrawal_2016 |
Passive Transfer of A Germline-like Neutralizing Human Monoclonal Antibody Protects Transgenic Mice Against Lethal Middle East Respiratory Syndrome Coronavirus Infection |
Agrawal, Anurodh Shankar; Ying, Tianlei; Tao, Xinrong; Garron, Tania; Algaissi, Abdullah; Wang, Yanping; Wang, Lili; Peng, Bi-Hung; Jiang, Shibo; Dimitrov, Dimiter S.; Tseng, Chien-Te K. |
2016 |
2016-08-19 |
COMM-USE |
N |
PMC4990914 |
27538452.0 |
10.1038/srep31629 |
g9vcchrh |
0.525964 |
|
|
| 16 |
Du_L_2016 |
Vaccines for the prevention against the threat of MERS-CoV |
Du, Lanying; Tai, Wanbo; Zhou, Yusen; Jiang, Shibo |
2016 |
2016-04-06 |
None |
N |
PMC5097835 |
26985862.0 |
10.1586/14760584.2016.1167603 |
eji6dw94 |
0.472172 |
|
Doremalen_2020, Zhang_2014 |
| 17 |
Du_L_2013 |
A Truncated Receptor-Binding Domain of MERS-CoV Spike Protein Potently Inhibits MERS-CoV Infection and Induces Strong Neutralizing Antibody Responses: Implication for Developing Therapeutics and Vaccines |
Du, Lanying; Kou, Zhihua; Ma, Cuiqing; Tao, Xinrong; Wang, Lili; Zhao, Guangyu; Chen, Yaoqing; Yu, Fei; Tseng, Chien-Te K.; Zhou, Yusen; Jiang, Shibo |
2013 |
2013-12-04 |
COMM-USE |
Y |
PMC3852489 |
24324708.0 |
10.1371/journal.pone.0081587 |
na54ad45 |
0.430568 |
|
|
| 18 |
LIU_R_2017 |
Newcastle disease virus-based MERS-CoV candidate vaccine elicits high-level and lasting neutralizing antibodies in Bactrian camels |
LIU, Ren-qiang; GE, Jin-ying; WANG, Jin-ling; SHAO, Yu; ZHANG, Hui-lei; WANG, Jin-liang; WEN, Zhi-yuan; BU, Zhi-gao |
2017 |
2017-10-31 |
PMC |
N |
PMC7128255 |
|
10.1016/s2095-3119(17)61660-5 |
fma8wq4z |
0.429992 |
|
Lau_S_2020 |
| 19 |
Wang_2016 |
MERS-CoV spike protein: Targets for vaccines and therapeutics |
Wang, Qihui; Wong, Gary; Lu, Guangwen; Yan, Jinghua; Gao, George F. |
2016 |
2016-09-30 |
PMC |
N |
PMC7113765 |
27468951.0 |
10.1016/j.antiviral.2016.07.015 |
fi2b29ih |
0.426635 |
|
|
| 20 |
Kim_E_2014 |
Immunogenicity of an adenoviral-based Middle East Respiratory Syndrome coronavirus vaccine in BALB/c mice |
Kim, Eun; Okada, Kaori; Kenniston, Tom; Raj, V. Stalin; AlHajri, Mohd M.; Farag, Elmoubasher A.B.A.; AlHajri, Farhoud; Osterhaus, Albert D.M.E.; Haagmans, Bart L.; Gambotto, Andrea |
2014 |
2014-10-14 |
PMC |
N |
PMC7115510 |
25192975.0 |
10.1016/j.vaccine.2014.08.058 |
mx5k92un |
0.417939 |
|
Adney_2019 |
| 21 |
Excler_2016 |
Toward Developing a Preventive MERS-CoV Vaccine—Report from a Workshop Organized by the Saudi Arabia Ministry of Health and the International Vaccine Institute, Riyadh, Saudi Arabia, November 14–15, 2015 |
Excler, Jean-Louis; Delvecchio, Christopher J.; Wiley, Ryan E.; Williams, Marni; Yoon, In-Kyu; Modjarrad, Kayvon; Boujelal, Mohamed; Moorthy, Vasee S.; Hersi, Ahmad Salah; Kim, Jerome H. |
2016 |
2016-08-23 |
PMC |
N |
PMC4982192 |
27439020.0 |
10.3201/eid2208.160229 |
ldwx1wyc |
0.369240 |
|
|
| 22 |
Xu_J_2019 |
Antibodies and vaccines against Middle East respiratory syndrome coronavirus |
Xu, Jiuyang; Jia, Wenxu; Wang, Pengfei; Zhang, Senyan; Shi, Xuanling; Wang, Xinquan; Zhang, Linqi |
2019 |
2019-06-06 |
COMM-USE |
Y |
PMC6567157 |
31169078.0 |
10.1080/22221751.2019.1624482 |
rbye73yv |
0.360353 |
|
Han_H_2018 |
| 23 |
Qiu_H_2016 |
Single-dose treatment with a humanized neutralizing antibody affords full protection of a human transgenic mouse model from lethal Middle East respiratory syndrome (MERS)-coronavirus infection |
Qiu, Hongjie; Sun, Shihui; Xiao, He; Feng, Jiannan; Guo, Yan; Tai, Wanbo; Wang, Yufei; Du, Lanying; Zhao, Guangyu; Zhou, Yusen |
2016 |
2016-06-14 |
None |
N |
PMC5109928 |
27312105.0 |
10.1016/j.antiviral.2016.06.003 |
gn812sh4 |
0.348875 |
|
|
| 24 |
Adney_2019 |
Efficacy of an Adjuvanted Middle East Respiratory Syndrome Coronavirus Spike Protein Vaccine in Dromedary Camels and Alpacas |
Adney, Danielle R.; Wang, Lingshu; van Doremalen, Neeltje; Shi, Wei; Zhang, Yi; Kong, Wing-Pui; Miller, Megan R.; Bushmaker, Trenton; Scott, Dana; de Wit, Emmie; Modjarrad, Kayvon; Petrovsky, Nikolai; Graham, Barney S.; Bowen, Richard A.; Munster, Vincent J. |
2019 |
2019-03-02 |
COMM-USE |
N |
PMC6466352 |
30832356.0 |
10.3390/v11030212 |
r8n0x6s9 |
0.345436 |
|
Lau_S_2020, Alagaili_2014, Adney_2014 |
| 25 |
Ying_2015 |
Development of human neutralizing monoclonal antibodies for prevention and therapy of MERS-CoV infections |
Ying, Tianlei; Li, Haoyang; Lu, Lu; Dimitrov, Dimiter S.; Jiang, Shibo |
2015 |
2015-02-28 |
None |
N |
PMC4308519 |
25456101.0 |
10.1016/j.micinf.2014.11.008 |
nf085z53 |
0.339764 |
|
Liang_2018, Han_H_2018 |
| 26 |
Chen_2017 |
Human Neutralizing Monoclonal Antibody Inhibition of Middle East Respiratory Syndrome Coronavirus Replication in the Common Marmoset |
Chen, Zhe; Bao, Linlin; Chen, Cong; Zou, Tingting; Xue, Ying; Li, Fengdi; Lv, Qi; Gu, Songzhi; Gao, Xiaopan; Cui, Sheng; Wang, Jianmin; Qin, Chuan; Jin, Qi |
2017 |
2017-06-15 |
PMC |
N |
PMC7107363 |
28472421.0 |
10.1093/infdis/jix209 |
lf7m7hx2 |
0.320249 |
|
Han_H_2018, Adney_2019 |
| 27 |
Li_K_2020 |
Single-Dose, Intranasal Immunization with Recombinant Parainfluenza Virus 5 Expressing Middle East Respiratory Syndrome Coronavirus (MERS-CoV) Spike Protein Protects Mice from Fatal MERS-CoV Infection |
Li, Kun; Li, Zhuo; Wohlford-Lenane, Christine; Meyerholz, David K.; Channappanavar, Rudragouda; An, Dong; Perlman, Stanley; McCray, Paul B.; He, Biao |
2020 |
2020-04-07 |
COMM-USE |
N |
PMC7157776 |
32265331.0 |
10.1128/mbio.00554-20 |
vmtfn78x |
0.305708 |
|
|
| 28 |
Okba_2017 |
Middle East respiratory syndrome coronavirus vaccines: current status and novel approaches |
Okba, Nisreen MA; Raj, V Stalin; Haagmans, Bart L |
2017 |
2017-04-30 |
PMC |
N |
PMC7102752 |
28412285.0 |
10.1016/j.coviro.2017.03.007 |
w1l8h8g8 |
0.301444 |
|
Adney_2019, Vergara-Alert_2017, Alagaili_2014 |


--- layout: archive title: Zulip Chat Archive permalink: /stream/113488-general/topic/building.20lean.html ---
I've just updated the OS X command line tools, I get a million warnings when trying to build Lean:
/Users/scott/projects/lean/lean/src/util/small_object_allocator.h:42:71: warning: 'operator delete' has a non-throwing exception specification but can still throw [-Wexceptions] inline void operator delete(void *, lean::small_object_allocator &) { lean_unreachable(); } ^ /Users/scott/projects/lean/lean/src/util/debug.h:23:156: note: expanded from macro 'lean_unreachable' #define lean_unreachable() { DEBUG_CODE({lean::notify_assertion_violation(__FILE__, __LINE__, "UNREACHABLE CODE WAS REACHED."); lean::invoke_debugger();}) throw lean::unreachable_reached(); } ^ /Users/scott/projects/lean/lean/src/util/small_object_allocator.h:42:13: note: deallocator has a implicit non-throwing exception specification inline void operator delete(void *, lean::small_object_allocator &) { lean_unreachable(); } ^ /Users/scott/projects/lean/lean/src/util/small_object_allocator.h:43:73: warning: 'operator delete[]' has a non-throwing exception specification but can still throw [-Wexceptions] inline void operator delete[](void *, lean::small_object_allocator &) { lean_unreachable(); } ^ /Users/scott/projects/lean/lean/src/util/debug.h:23:156: note: expanded from macro 'lean_unreachable' #define lean_unreachable() { DEBUG_CODE({lean::notify_assertion_violation(__FILE__, __LINE__, "UNREACHABLE CODE WAS REACHED."); lean::invoke_debugger();}) throw lean::unreachable_reached(); } ^
Presumably we want to switch off these warnings?
{% endraw %}Last updated: Apr 24 2020 at 19:02 UTC


Congratulations on reaching the final project of the Robotics Nanodegree!
Previously, you worked on the Semantic Segmentation lab where you built a deep learning network that locates a particular human target within an image. For this project, you will utilize what you implemented and learned from that lab and extend it to train a deep learning model that will allow a simulated quadcopter to follow around the person that it detects!
Most of the code below is similar to the lab with some minor modifications. You can start with your existing solution, and modify and improve upon it to train the best possible model for this task.
You can click on any of the following to quickly jump to that part of this notebook:
We have provided you with a starting dataset for this project. Download instructions can be found in the README for this project's repo. Alternatively, you can collect additional data of your own to improve your model. Check out the "Collecting Data" section in the Project Lesson in the Classroom for more details!
import os
import glob
import sys
import tensorflow as tf
from scipy import misc
import numpy as np
from tensorflow.contrib.keras.python import keras
from tensorflow.contrib.keras.python.keras import layers, models
from tensorflow import image
from utils import scoring_utils
from utils.separable_conv2d import SeparableConv2DKeras, BilinearUpSampling2D
from utils import data_iterator
from utils import plotting_tools
from utils import model_tools
In the Classroom, we discussed the different layers that constitute a fully convolutional network (FCN). The following code will introduce you to the functions that you need to build your semantic segmentation model.
The Encoder for your FCN will essentially require separable convolution layers, due to their advantages as explained in the classroom. The 1x1 convolution layer in the FCN, however, is a regular convolution. Implementations for both are provided below for your use. Each includes batch normalization with the ReLU activation function applied to the layers.
def separable_conv2d_batchnorm(input_layer, filters, strides=1):
output_layer = SeparableConv2DKeras(filters=filters,kernel_size=3, strides=strides,
padding='same', activation='relu')(input_layer)
output_layer = layers.BatchNormalization()(output_layer)
return output_layer
def conv2d_batchnorm(input_layer, filters, kernel_size=3, strides=1):
regularizer = tf.contrib.layers.l2_regularizer(scale=0.1)
output_layer = layers.Conv2D(filters=filters, kernel_size=kernel_size, strides=strides,
padding='same', activation='relu', kernel_regularizer=regularizer)(input_layer)
output_layer = layers.BatchNormalization()(output_layer)
return output_layer
The following helper function implements the bilinear upsampling layer. Upsampling by a factor of 2 is generally recommended, but you can try out different factors as well. Upsampling is used in the decoder block of the FCN.
def bilinear_upsample(input_layer):
output_layer = BilinearUpSampling2D((2,2))(input_layer)
return output_layer
In the following cells, you will build an FCN to train a model to detect and locate the hero target within an image. The steps are:
encoder_block
decoder_block
Create an encoder block that includes a separable convolution layer using the separable_conv2d_batchnorm()
function. The filters
parameter defines the size or depth of the output layer. For example, 32 or 64.
def encoder_block(input_layer, filters, strides):
# Create a separable convolution layer using the separable_conv2d_batchnorm() function.
output_layer = separable_conv2d_batchnorm(input_layer, filters, strides=strides)
return output_layer
The decoder block is comprised of three parts:
def decoder_block(small_ip_layer, large_ip_layer, filters):
# Upsample the small input layer using the bilinear_upsample() function.
upsampled = bilinear_upsample(small_ip_layer)
# Concatenate the upsampled and large input layers using layers.concatenate
output = layers.concatenate([upsampled, large_ip_layer])
# Add two separable convolution layers
output = separable_conv2d_batchnorm(output, filters)
output = separable_conv2d_batchnorm(output, filters)
return output
Now that you have the encoder and decoder blocks ready, go ahead and build your FCN architecture!
There are three steps:
def fcn_model(inputs, num_classes):
# Add Encoder Blocks.
enc1 = encoder_block(inputs, filters=16, strides=2)
enc2 = encoder_block(enc1, filters=32, strides=2)
enc3 = encoder_block(enc2, filters=64, strides=2)
enc4 = encoder_block(enc3, filters=128, strides=2)
# Add 1x1 Convolution layer using conv2d_batchnorm().
conv_1x1 = conv2d_batchnorm(enc4, 1024, kernel_size=1, strides=1)
# Add the same number of Decoder Blocks as the number of Encoder Blocks
dec1 = decoder_block(conv_1x1, enc3, 128)
dec2 = decoder_block(dec1, enc2, 64)
dec3 = decoder_block(dec2, enc1, 32)
x = decoder_block(dec3, inputs, 16)
# The function returns the output layer of your model. "x" is the final layer obtained from the last decoder_block()
return layers.Conv2D(num_classes, 1, activation='softmax', padding='same')(x)
The following cells will use the FCN you created and define an ouput layer based on the size of the processed image and the number of classes recognized. You will define the hyperparameters to compile and train your model.
Please Note: For this project, the helper code in data_iterator.py
will resize the copter images to 160x160x3 to speed up training.
"""
DON'T MODIFY ANYTHING IN THIS CELL THAT IS BELOW THIS LINE
"""
image_hw = 160
image_shape = (image_hw, image_hw, 3)
inputs = layers.Input(image_shape)
num_classes = 3
# Call fcn_model()
output_layer = fcn_model(inputs, num_classes)
Define and tune your hyperparameters.
learning_rate = 0.002
batch_size = 128
num_epochs = 20
steps_per_epoch = 80
validation_steps = 20
workers = 8
"""
DON'T MODIFY ANYTHING IN THIS CELL THAT IS BELOW THIS LINE
"""
# Define the Keras model and compile it for training
model = models.Model(inputs=inputs, outputs=output_layer)
model.compile(optimizer=keras.optimizers.Adam(learning_rate), loss='categorical_crossentropy')
# Data iterators for loading the training and validation data
train_iter = data_iterator.BatchIteratorSimple(batch_size=batch_size,
data_folder=os.path.join('..', 'data', 'train'),
image_shape=image_shape,
shift_aug=True)
val_iter = data_iterator.BatchIteratorSimple(batch_size=batch_size,
data_folder=os.path.join('..', 'data', 'validation'),
image_shape=image_shape)
logger_cb = plotting_tools.LoggerPlotter()
callbacks = [logger_cb]
model.fit_generator(train_iter,
steps_per_epoch = steps_per_epoch, # the number of batches per epoch,
epochs = num_epochs, # the number of epochs to train for,
validation_data = val_iter, # validation iterator
validation_steps = validation_steps, # the number of batches to validate on
callbacks=callbacks,
workers = workers)
# Save your trained model weights
weight_file_name = 'model_weights'
model_tools.save_network(model, weight_file_name)
Now that you have your model trained and saved, you can make predictions on your validation dataset. These predictions can be compared to the mask images, which are the ground truth labels, to evaluate how well your model is doing under different conditions.
There are three different predictions available from the helper code provided:
# If you need to load a model which you previously trained you can uncomment the codeline that calls the function below.
# weight_file_name = 'model_weights'
# restored_model = model_tools.load_network(weight_file_name)
The following cell will write predictions to files and return paths to the appropriate directories.
The run_num
parameter is used to define or group all the data for a particular model run. You can change it for different runs. For example, 'run_1', 'run_2' etc.
run_num = 'run_1'
val_with_targ, pred_with_targ = model_tools.write_predictions_grade_set(model,
run_num,'patrol_with_targ', 'sample_evaluation_data')
val_no_targ, pred_no_targ = model_tools.write_predictions_grade_set(model,
run_num,'patrol_non_targ', 'sample_evaluation_data')
val_following, pred_following = model_tools.write_predictions_grade_set(model,
run_num,'following_images', 'sample_evaluation_data')
Now lets look at your predictions, and compare them to the ground truth labels and original images. Run each of the following cells to visualize some sample images from the predictions in the validation set.
# images while following the target
im_files = plotting_tools.get_im_file_sample('sample_evaluation_data','following_images', run_num)
for i in range(3):
im_tuple = plotting_tools.load_images(im_files[i])
plotting_tools.show_images(im_tuple)
# images while at patrol without target
im_files = plotting_tools.get_im_file_sample('sample_evaluation_data','patrol_non_targ', run_num)
for i in range(3):
im_tuple = plotting_tools.load_images(im_files[i])
plotting_tools.show_images(im_tuple)
# images while at patrol with target
im_files = plotting_tools.get_im_file_sample('sample_evaluation_data','patrol_with_targ', run_num)
for i in range(3):
im_tuple = plotting_tools.load_images(im_files[i])
plotting_tools.show_images(im_tuple)
Evaluate your model! The following cells include several different scores to help you evaluate your model under the different conditions discussed during the Prediction step.
# Scores for while the quad is following behind the target.
true_pos1, false_pos1, false_neg1, iou1 = scoring_utils.score_run_iou(val_following, pred_following)
# Scores for images while the quad is on patrol and the target is not visable
true_pos2, false_pos2, false_neg2, iou2 = scoring_utils.score_run_iou(val_no_targ, pred_no_targ)
# This score measures how well the neural network can detect the target from far away
true_pos3, false_pos3, false_neg3, iou3 = scoring_utils.score_run_iou(val_with_targ, pred_with_targ)
# Sum all the true positives, etc from the three datasets to get a weight for the score
true_pos = true_pos1 + true_pos2 + true_pos3
false_pos = false_pos1 + false_pos2 + false_pos3
false_neg = false_neg1 + false_neg2 + false_neg3
weight = true_pos/(true_pos+false_neg+false_pos)
print(weight)
# The IoU for the dataset that never includes the hero is excluded from grading
final_IoU = (iou1 + iou3)/2
print(final_IoU)
# And the final grade score is
final_score = final_IoU * weight
print(final_score)


Bananagrams Online
Everyone's favorite board-free Scrabble, now socially-distant
Features
Flexible Lobbies
Control the size and visibility of your lobby to play with strangers or with friends. Give yourself and your lobbies names for easy identification.
Drag and Drop System
Drag and drop your tiles into a large, scrollable grid system. Build your crosswords quickly without ever having to worry about running out of space.
Full Bunch Usage
Just like in a physical game of Bananagrams, every piece in the bunch will be used, without repeats, until no more tiles may be peeled. Say goodbye to the lucky and unlucky bunches that plague Bananagrams over the phone.


We love people who love building things.
Embracing courage, curiosity and dedication to craftmanship in technology and across all disciplines.

We like to rethink things. As a matter of fact, everything. We fell in love with the speed of technological
change. The uncertainty of things. The adventure of exploration. Yes, it can be rather daunting for some,
but for us, we like to dive in head first.
Whether we love to strategise, design or code, we all speak one common language – a language of passion, empathy
and challenge. Simply because we want to build products that matter. For now. For later.
We believe two heads are always better than one. And a whole team of heads is even better. That’s how we work.
With no alpha leaders and no beta teams.
Sounds like you?
Join us!


For me, APIs (application program interfaces) ~~are~~ were like Homer’s island of Sirens - a beautiful sounding place where programmer happiness abounds but get to close and you’ll die a thousand deaths by poor documentation and JSON (Javascript Object Notation) spaghetti.
Summary: Getting acclimated with Bootstrap setup so you can run and play with it.
In my time since graduating GA’s Web Development Immersive, I have been doing a lot of indulging. Specifically, I have allowed myself to spend time read what I want online. (I actually gave myself formal permission on a sticky note, signed and dated, stuck to my desk near my computer as solemn reminder to never forget to have fun).
I wanted to read up on the basics of how teams deploy products. While at GA, we were able to work on a group project using the Agile methodology and scrum tactics but because we worked so closely together, merging branches and getting our app to production was fairly easy.
This post is not about programming, its purpose is to add a little substance to this site’s cover photo and share a little bit about myself.
Just released is the RedMonk Programming Language Rankings for Q1 2015, you can find a link here.
My first iteration of turaew.io proved successful but when I shared the site with my wife, she could not get past how horrible it looked on her mobile phone.
I will freely admit that when faced with the task of learning some new programming framework or language, I am filled with a mixture of excitement and anxiety.
Last Tuesday, I gave a talk at General Assembly DC’s first New Tech UnConference on Cognitive Science.
I found there are a lot of options for starting a blog online. Wordpress and Ghost and a new one called Jekyll.
After doing some research I found that a static site generator like Jekyll offers some advantages over dynamic sites like Wordpress:
Before creating this site, I agonized on whether to write a blog. I always liked the idea of a blog but did not think I would make a good blogger for two primary reasons:
I am a functional introvert who has learned to loath small talk.


AP Top Massachusetts Headlines at 3:37 a.m. EST
by EndPlayMassachusetts House passes flavored tobacco ban, vaping tax
AP sources: Ex-Gov. Patrick says he'll make presidential bid
Massachusetts fire lieutenant dies battling house fire
Ex-insurance exec gets 6 months in college admissions scam
Governor names new head of Massachusetts State Police
Massachusetts man charged in shooting death of father
Prosecutors: Road rage led to death of Massachusetts man
Warren files for NH primary, scorns ‘billionaires'


“To begin from the top: I have five sabre cuts on the crown of the head and three on the left temple, all fractures from which much bone has come away; one on my left cheek which fractured the jaw bone and has divided the ear, forming a very unsightly wound; one over the right temple and a dreadful gash on the back of the neck, which slightly grazed the windpipe; a musket ball in the hip, which made its way through my back, slightly grazing the backbone; five sabre cuts on my right arm and hand, three of the fingers broken, the hand cut three-fourths across, and the wrist bones cut through; three cuts on the left arm, the bone of which has been broken but is again uniting; one slight wound on the right leg and two with one dreadful gash on the left, to say nothing of a cut across the fingers of my left hand, now healed up.”
Almost as an afterthought he added that on arrival at Sidi el Muktar he had caught the plague—“a dreadful malady somewhat similar to yellow fever in its symptoms”—and had spent nine days “so ill with fever that it was presumed, expected and hoped that I should die”.  “I am nevertheless doing well,” he concluded, writing with only the thumb and middle finger of his left hand, “and hope yet to return to England with much important geographical information.”
… “My father used often to accuse me of a want of common sense,” he once confided to his sister, “‘Tis true, I never possessed any, nor ever shall.”
Gordon Laing in Africa in 1825, from Barrow's Boys by Fergus Fleming (1998)


Package b2p.search.aima.minmax
Class MinMaxAlphaBetaSearch
- java.lang.Object
-
- b2p.search.aima.minmax.MinMaxAlphaBetaSearch
-
- All Implemented Interfaces:
java.util.concurrent.Callable<java.lang.Integer>
public class MinMaxAlphaBetaSearch extends java.lang.Object implements java.util.concurrent.Callable<java.lang.Integer>
This class represents a Minimax search with alpha-beta pruning to be ran on a game state. It implementsCallable
in order to allow for asynchronous execution.- Author:
- Alessandro Buldini, Alessandro Pomponio, Federico Zanini
- See Also:
- AIMA Java
-
-
Constructor Summary
Constructors Modifier Constructor Description protected
MinMaxAlphaBetaSearch(IterativeDeepening strategy, IState state, IAction action, it.unibo.ai.didattica.competition.tablut.domain.State.Turn player)
Builds a MinMaxAlphaBetaSearch object given the strategy, the current state of the game, the initial action and the player for whom the best decision has to be made
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description java.lang.Integer
call()
Starts searching for the best decision to be made given an initial actionint
maxValue(IState state, it.unibo.ai.didattica.competition.tablut.domain.State.Turn player, int alpha, int beta, int depth)
function needed to implement correctly the alpha-beta pruning: detects the maximum value between two possible states and prunes all the sub-trees that won't be explored according to the current heuristic functionint
minValue(IState state, it.unibo.ai.didattica.competition.tablut.domain.State.Turn player, int alpha, int beta, int depth)
function needed to implement correctly the alpha-beta pruning: detects the minimum value between two possible states and prunes all the sub-trees that won't be explored according to the current heuristic function
-
-
-
Constructor Detail
-
MinMaxAlphaBetaSearch
protected MinMaxAlphaBetaSearch(IterativeDeepening strategy, IState state, IAction action, it.unibo.ai.didattica.competition.tablut.domain.State.Turn player)
Builds a MinMaxAlphaBetaSearch object given the strategy, the current state of the game, the initial action and the player for whom the best decision has to be made- Parameters:
strategy
- instance ofIterative Deepening
strategystate
- current state of the gameaction
- initial action performed for this thread based on which the function's decision tree is createdplayer
- player for whom the best decision has to be made- See Also:
IterativeDeepening
-
-
Method Detail
-
maxValue
public int maxValue(IState state, it.unibo.ai.didattica.competition.tablut.domain.State.Turn player, int alpha, int beta, int depth)
function needed to implement correctly the alpha-beta pruning: detects the maximum value between two possible states and prunes all the sub-trees that won't be explored according to the current heuristic function- Parameters:
state
- current state of the gameplayer
- player that performs the movealpha
- alpha valuebeta
- beta valuedepth
- current depth- Returns:
- maximum heuristic value between two states within the decision tree
- See Also:
IState
-
minValue
public int minValue(IState state, it.unibo.ai.didattica.competition.tablut.domain.State.Turn player, int alpha, int beta, int depth)
function needed to implement correctly the alpha-beta pruning: detects the minimum value between two possible states and prunes all the sub-trees that won't be explored according to the current heuristic function- Parameters:
state
- current state of the gameplayer
- player that performs the movealpha
- alpha valuebeta
- beta valuedepth
- current depth- Returns:
- minimum heuristic value between two states within the decision tree
- See Also:
IState
-
call
public java.lang.Integer call()
Starts searching for the best decision to be made given an initial action- Specified by:
call
in interfacejava.util.concurrent.Callable<java.lang.Integer>
- Returns:
- an integer containing the best heuristic value according to Iterative Deepening MiniMax search with alpha-beta pruning
-
-


interface EnvironmentInterface : ServerBaseURL
Payment Highway environment interface
baseURL
abstract var baseURL: String
Environment
enum class Environment : EnvironmentInterface
Payment Highway environment


What is a micro archive? A micro archive is a snapshot of a fixed (evolving) set of URLs that are representative for some object or entity (at a given time). Hence, such an archive can be used to describe and / or derive information about its subject at the time of the crawl.
Create your own micro archive for an entity or object of your choice by either defining a set of URLs manually or loading / extracting a crawl specification from some URL:


TO WHOM IT MAY CONCERN:
We hereby certify that {{nombre}}, whose ID number is {{matricula}}, is currently enrolled in this Institute in the present period from {{fechas_de_periodo}}. He/She is registered as a student in {{carrera}} major, semester {{semestre}}, inscribed with the following subjects:
{{nombre_materias_inscritas}}
We also wish to inform you that the vacation period will be from {{periodo_de_vacaciones}}. This Institute functions under a Free College University legal regime in accordance with the Presidential Decree dated the July 14th, 1952 and published on the September 12th, 1952 in the Official Journal of the Federation. This decree validates nationwide the studies imparted by the Instituto Tecnologico y de Estudios Superiores de Monterrey (Monterrey Institute of Technology and Higher Education).
In Accord No. 3438, issued by the Public Education Secretary on the 28th of February of 1974 and published in the Official Journal of the Federation on the 5th of March of the same year, the aforementioned Decree was extended to validate the studies imparted by the Instituto Tecnologico y de Estudios Superiores de Monterrey in any of its National Campus in any city within the Mexican Republic. We additionally inform you that our Institution is registered in the SEP under Code DEC-520912 and that its registration number in the General Direction of Professions is 190002.
This Institute is also a member of the Asociacion Nacional de Universidades e Institutos de Enseñanza Superior de la Republica Mexicana (National Association of Universities and Superior Studies Institutes of the Mexican Republic); as well as an extraterritorial member of the Southern Association of Colleges and Schools, whereas all of the courses imparted by the Institute are recognized by the Universities in the United States of America.
We hereby extend this DOCUMENT for whatever legal purposes the student may require, in Monterrey city, Nuevo León on {{fecha_actual}}.
Sincerely,
Academic Administration Department
Tecnológico De Monterrey
Campus Monterrey


| 44 | (A) | he was a Marynere of Mighte & a marchande bothe |
| 44 | (C) | And was a maryner myche . & marchaunte in fere |
| 44 | (D) | And was a Mariner mycħ & marchaunt y-fere |
| 43 | (E) | & was a maryneer meche . & marchaunt also |
| (Ex) | ---- no text ---- | |
| 44 | (L) | & was a marener myche & marchaunt boþe |
| 39 | (P) | And was maryner myche & marchand bothe |
| 44 | (U) | And was a maryner muche / and merchant in fere |
| (V) | ---- no text ---- |