Skip to content

Instantly share code, notes, and snippets.

type FooBar = { foo :: String , bar? :: Int }
r :: FooBar
r = { foo: "foo" }
foo :: String
foo = r.foo -- "foo"
bar :: Maybe Int
bar = r.bar -- Nothing
@gabejohnson
gabejohnson / Main.purs
Last active June 10, 2020 17:07
A DSL for labeled template literals
module Main where
import Prelude
import Effect (Effect)
import Data.Array (snoc)
import Data.Foldable (fold)
import Data.Tuple.Nested (type (/\), (/\))
import TryPureScript (h1, render, text)
// Adapted from https://github.com/russellmcc/fantasydo/blob/master/index.js
// The `monad` argument has been added to avoid modifying the prototype of
// the yielded value to provide `pure` and `bind`.
// Note:
// This algorithm is not stack safe, and is inefficient due to the
// requirement that we bring the generator up to the previous state on each
// iteration.
// I suspect it's particularly bad for arrays. I may come back to this at
// some point to calculate just how bad it really is.
const Do = monad => genFn => {
@gabejohnson
gabejohnson / paths.js
Last active August 9, 2018 18:46
Simple DSL for accessing/updating deeply nested data
/*
Calling _.foo.bar with a value returns the value at the end of that path (if it exists), `undefined` otherwise.
Constructing _.foo.bar with a function returns a function that immutably updates a value if the path matches, returns the original otherwise.
Usage:
> [{foo: {bar: 1}}, {foo: {bar: 2}}, {foo: {bar: 3}}, {foo: {bur: 4}}].map(_.foo.bar)
[1, 2, 3, undefined]
@gabejohnson
gabejohnson / Main.purs
Last active June 4, 2020 03:26
Record shenanigans
module Main where
import Prelude
import Record.Unsafe (unsafeDelete)
import Effect (Effect)
import TryPureScript (h1, text, render)
r :: forall t. Record (x :: Boolean, x :: Int, x :: String, x :: t)
r = { x: [3] } { x = true }
r2 :: forall t. Record (x :: Boolean, x :: Int, x :: String, x :: t)
@gabejohnson
gabejohnson / ramda-sanctuary.md
Last active August 22, 2018 16:48 — forked from Avaq/ramda-sanctuary.md
Comprehensive Ramda to Sanctuary list
Ramda Sanctuary
add(a, b) add(a, b)
addIndex(f) ``
adjust(f, i, xs) ``
all(f, xs) ``
allPass(fs, x) allPass(fs, x)
always(x) K(x)
and(a, b) and(a, b)
any(f, x) ``
@gabejohnson
gabejohnson / infix.js
Last active December 19, 2018 16:52
Because I'm lazy and mixfix w/ proxies is slow
var isWrapper = Symbol('isWrapper');
function _(arg, args=[], ops=[]) {
const myArgs = args.concat([arg]);
const myOps = ops.slice(0);
const f = ([op]) => (
myOps.push(op),
wrap(arg2 => _(arg2, myArgs, myOps), myArgs, myOps)
);
@gabejohnson
gabejohnson / fix.js
Last active December 19, 2018 16:52
So you know how you've always wanted to write custom *fix operators? You haven't?!?! Well this isn't for you then
// fix.js
// _has :: String => Boolean
var _has = k => _[k] != null;
// last :: Array a => a?
var last = xs => xs[xs.length-1];
// copyArray :: Array a => Array a
var copyArray = xs => xs.slice(0);
@gabejohnson
gabejohnson / fix.js
Last active December 19, 2018 14:27
You want mixfix? You got it!
function _(x) {
if (x instanceof _) return new _(x._);
if (!(this instanceof _)) return new _(x);
this._ = x;
}
_.mixfix = function mixfix(pattern, f) {
const [name, ...names] = pattern.split('_');
let startIndex = name === '' ? 1 : 0;

Types

In Fantasy Land, types are specified by an object containing a catamorphic method cata. cata has an arity matching the number of constructor functions belonging to each type. Each argument to cata is either:

  1. a value
  2. a function with an arity matching the number of arguments to the constructor function.
    1. Each function argument to cata must return a value of the same type as