Skip to content

Instantly share code, notes, and snippets.

View dtipson's full-sized avatar

Drew dtipson

View GitHub Profile
@dtipson
dtipson / IO plus Array & Promise helpers.js
Last active August 26, 2024 01:15
Bare bones FP type utility lib so we can play around with functions that capture the composition of DOM read/writes, but in a pure way
// Let's make it possible to create pure functions even when we're
// dealing with impure operations that would have side effects!
// First we'll need a "Type" that can contain a (sometimes impure) function
function IO(fn) {
if (!(this instanceof IO)) {//make it simpler for end users to create a type without "new"
return new IO(fn);
}
this.runIO = fn;//IO now provides an extra control layer that allows the composition of unexecuted effects
// Finally wrapped your head around Promises? Time to toss out all that knowledge and learn the functional alternative!
// Here's a super simple implementation of a Task "type"
const __Task = fork => ({fork})
// Absurdly simple! All we're doing is using a function that returns some unknown value, by name, in an object.
// At this point "fork" is just a cute name though: what matters is how we use it.
// What makes Task a "Task" is that is that the "fork" value here... will be a higher-order function.
// Here's a usage example, already fully functional, already nearly as powerful as Promise!
@dtipson
dtipson / responsive-request-desktop-site.js
Last active February 17, 2024 20:49
How to make responsive sites better respect the "Request a desktop site" feature on modern mobile browsers.
/*
Enable the "Request Desktop Site" functions on mobile chrome (android and iOS) allow users to see desktop layouts on responsive sites. Note that this is distinct from "opt out of mobile!" buttons built into your site: this is meant to work with the browser's native opt-in/opt-out functionality.
Since these functions work, in part, by simply spoofing the user agent to pretend to be desktop browsers, all we have to do is just remember that the browser once claimed to be android earlier in the same session and then alter the viewport tag in response to its fib.
Here's an example viewport tag <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> that we'd be setting to scaleable-yes,max scale=2. That's just an example of something that works on the site I was building: you should customize the "desktop" viewport content setting to whatever works for your site's needs. If you wanted, you could stick this code in the head just after the primary viewport tag so that the br
@dtipson
dtipson / spreadBatchesAsyncGen.js
Last active January 5, 2024 16:00
Spreading out a generator of arrays into a generator of items
// spreadBatchesAsyncGen :: Iterator[[...Promises]] -> AsyncGenerator[[...Promises]]
const spreadBatchesAsyncGen = async function* (iterableOfPromises) {
for (let array of iterableOfPromises) {
yield* await Promise.all(array)
}
}
@dtipson
dtipson / complete-pipeline-two.js
Last active December 26, 2023 15:08
An even simpler pipeline
const outputs = await pipe(
postIds,// array of numbers, which is... already an iterable
mapGen(fetchById),// generator of an array of eventually all resolved promises (requested in chunks of 3)
chunkGen(5),// generator of arrays of 5 promises, our "batch"
spreadBatchesAsyncGen,// async generator of individual resolved promises
forEachAsyncGen(renderPost)// Promise of an array of numbers
)
@dtipson
dtipson / complete-pipeline.js
Last active December 26, 2023 03:59
A pipeline version
await pipe(
postIds[Symbol.iterator](),// creates a generator from a plain array of postIds
chunkGen(5),// generator that pulls in 5 numbers and yields them out in arrays of 5
mapGen(map(fetchById)),// generator that takes in arrays of numbers & turns them into arrays of requests
spreadBatchesAsyncGen,// async generator that spreads arrays of resolved promises & emits one promise at a time
forEachAsyncGen(renderPost)// a function that consumes the generator & does something with each result
)
@dtipson
dtipson / batchTasks-spread.js
Last active December 25, 2023 19:42
Revised batchTasks generator
export async function* batchTasks(tasks = [], limit = 5, taskCallback = r => r) {
for (let i = 0; i < tasks.length; i = i + limit) {
const batch = tasks.slice(i, i + limit)
yield* await Promise.all(
batch.map((task) => task().then(taskCallback))
)
}
}
@dtipson
dtipson / cellular automata with quasi-comonads.js
Last active November 9, 2021 14:41
Using a comonad(ish) pattern to create cellular automata in a more functional way. Inspired by this episode of funfunfunction: https://www.youtube.com/watch?v=bc-fVdbjAwk
/*
Native Arrays are not great structures for cellular automata.
Non-empty, circular, doubly-linked lists would be ideal...
but all we really need to do is write a comonadic-like interface
such that it _pretends_ that the array is circular, and can thus
pass the exfn below a sort of "local" slice of an Array as if it were circular.
So you can mostly ignore the implementation mess below
*/
Array.prototype.extendNear = function(exfn){
const len = this.length;
/*
So, let's play with some Semigroups and (maybe?) Monoids for combining lists in interesting ways
*/
//This one is pretty straightforward
//Union (keep all values from both lists, but no repeats)
const Union = function(xs){
if (!(this instanceof Union)) {
return new Union(xs);
}
var object = {
value:5,
increment(){ return ++this.value; }
};
/*
But of course, even though that value is central to what the object is,
it's not really a _primitive_ value in the sense that we can directly coerce it into a number or string:
*/