Skip to content

Instantly share code, notes, and snippets.

TL/DR Not every type hole is harmful.

[Disclaimer: The following code is typed with scriptum, a type validator for dynamically typed Javascript. It has its roots in Haskell's Hindley-Milner based type system.]

It helps to consider mutations to get a better intuition. Mutations are a side effect and thus harmful. However, if we manage to hedge side effects so that we don't lose track of them, then we can benefit from the flexibility they provide without having to suffer the consequences.

For mutations this merely essentially means ensuring they stay local. Local mutations are fine in most cases. The same applies to type holes.

Let's work through some code to see if this claim holds. Gradual typing is a trade-off. Good coding means to find the most promising trade-offs.

@ivenmarquardt
ivenmarquardt / immutable-array.md
Last active April 7, 2020 18:59
An immutable array disguised as a regular one in Javascript

Iarray is an immutable Array that can be used like a regular Array in some cases and offers the following efficient operations for huge amounts of data:

  • get/set/del an element
  • unshift/shift an element (cons/uncons in FP terms)
  • push/pop an element (snoc/unsnoc in FP terms)
  • concatenate two Iarrays (append in FP terms)

You can use Iarray like a regular Array in the following situations:

  • xs[0] (get through bracket syntax)

Asynchronous operations entail race conditions provided they are evaluated in parellel. However, a counter should always be evaluated in sequence as per logic. I'd claim this reveals another flaw of Javascript's Promise type: It is actually a blend of the two types (sequential) Task and Parallel. While the former is a monad the latter is only an applicative.

Bergi has a point, of course. Asynchronous operations in parallel should solely rely on immutable data. However, operations that are inherently sequential should be evaluated as such and thus it doesn't matter if the underlying data is immutable or not.

I am not that versed in dealing with promises, so I probably doesn't use the type correctly. However, it should be enough to illustrate my point.

@ivenmarquardt
ivenmarquardt / lazy-evaluation.js
Last active May 18, 2018 20:37
Lazy evaluation, lazy getters, eta reduction, function composition, implicit thunks through deferred type
// Lazy Getters
/* What enables Tail Recursion Modulo Cons in Javascript is a thunk in Weak Head Normal Form.
An expression in weak head normal form has been evaluated to the outermost data constructor,
but contains sub-expressions that may not have been fully evaluated. In Javascript only thunks
can prevent sub-expressions from being immediately evaluated. */
const cons = (head, tail) => ({head, tail});
@ivenmarquardt
ivenmarquardt / value-polymorphism.js
Last active May 4, 2018 14:38
Value Polymorphism with Clojure Style Overloaded Functions
// type constructor
const toTypeTag = x => {
const tag = Object.prototype.toString.call(x);
return tag.slice(tag.lastIndexOf(" ") + 1, -1);
};
const TAG = Symbol("TAG");
@ivenmarquardt
ivenmarquardt / todo-app.js
Last active May 14, 2022 03:36
Functional Reactive Programming (FRP) implemented with a couple rules, types and combinators
// Based on this blog post: https://medium.com/@iquardt/taming-the-dom-50c8f1a6e892
/* RULES
* Only the program may manipulate the output display, never the user
* User input is presented in the form of events
* GUI elements generate events only in response to user input, never in response to program output
*/
@ivenmarquardt
ivenmarquardt / frp.js
Created April 3, 2018 13:05
Functional reactive programming types: Event(-Stream) / Behavior
// data constructor
const Data = name => Dcons => {
const Data = k => {
const t = new Tcons();
t[`run${name}`] = k;
t.tag = name;
return t;
};
@ivenmarquardt
ivenmarquardt / effect.js
Last active March 5, 2018 16:14
Effect type applicative computation - deferred runtime error
const Data = Tcons => Dcons => {
const Data = x => {
const t = new Tcons();
t[`run${Tcons.name}`] = x;
t.tag = Tcons.name
return t;
};
return Dcons(Data);
};
@ivenmarquardt
ivenmarquardt / typecheck.js
Last active March 8, 2017 13:08
Dynamic Javascript type checker for curried functions (functional programming, currying, partial application, debug, debugging)
const reflectf = (...preds) => (...arities) => (f, tag = f.name) => (...args) => {
if (args.length !== arities[0]) {
throw new TypeError(`${tag} expects an ${arities[0]}-ary lambda (${args.length}-ary given)`);
}
args.forEach((arg, i) => preds[i](arg));
const r = f(...args);
if (args.length === arities.length) return (preds[1](r), r);
@ivenmarquardt
ivenmarquardt / foldlk.js
Created October 17, 2016 20:05
Catamorphism, fold, lazy evaluation, continuation, short circuiting, iteration
const foldlk = f => acc => xs => {
const next = (acc, key) => xs.length === key
? acc
: f(acc) (xs[key], acc => next(acc, key + 1));
return next(acc, 0);
};
const every = f => foldlk(x => (y, k) => f(y) ? k(true) : false) (true);
const some = f => foldlk(x => (y, k) => f(y) ? true : k(false)) (false);