Skip to content

Instantly share code, notes, and snippets.

Avatar

Andy Matuschak andymatuschak

View GitHub Profile
@andymatuschak
andymatuschak / gist:c5f2b8b68821a95e5b339bfcd4bfcee1
Last active Jul 21, 2020
late-bound React hook callbacks, avoiding subtree re-renders when event callback deps change
View gist:c5f2b8b68821a95e5b339bfcd4bfcee1
function useWeakRef<T>(value: T): React.MutableRefObject<T> {
const ref = useRef(value);
useEffect(() => {
ref.current = value;
}, [value]);
return ref;
}
function useByrefCallback<Args extends unknown[], Result>(
callback: (...args: Args) => Result,
@andymatuschak
andymatuschak / clozePromptPlugin.ts
Last active Feb 22, 2020
parsing SRS prompts from Markdown
View clozePromptPlugin.ts
import mdast from "mdast";
import remarkParse from "remark-parse";
import remarkStringify from "remark-stringify";
import unified from "unified";
import unist from "unist";
import { clozeNodeType, ClozePromptNode } from "./index";
// TODO: don't match clozes inside code and html blocks
const clozeRegexp = /^{(.+?)}/;
export default function clozePlugin(this: unified.Processor) {
View gist:366d88341b754a012cb5cb6776ad9c84
Day 0. Due: 100∑ [21, 79, 0, 0, 0, 0, 0, 0] Reviewed: 100 States: [13, 18, 69, 0, 0, 0, 0, 0] (average 1.56)
Day 1. Due: 31∑ [13, 18, 0, 0, 0, 0, 0, 0] Reviewed: 31 States: [5, 10, 85, 0, 0, 0, 0, 0] (average 1.8)
Day 2. Due: 15∑ [5, 10, 0, 0, 0, 0, 0, 0] Reviewed: 15 States: [0, 5, 95, 0, 0, 0, 0, 0] (average 1.95)
Day 3. Due: 74∑ [0, 5, 69, 0, 0, 0, 0, 0] Reviewed: 74 States: [0, 19, 31, 50, 0, 0, 0, 0] (average 2.31)
Day 4. Due: 48∑ [0, 19, 29, 0, 0, 0, 0, 0] Reviewed: 48 States: [4, 9, 17, 70, 0, 0, 0, 0] (average 2.53)
Day 5. Due: 15∑ [4, 9, 2, 0, 0, 0, 0, 0] Reviewed: 15 States: [4, 3, 21, 72, 0, 0, 0, 0] (average 2.61)
Day 6. Due: 7∑ [4, 3, 0, 0, 0, 0, 0, 0] Reviewed: 0 States: [4, 3, 21, 72, 0, 0, 0, 0] (average 2.61)
Day 7. Due: 22∑ [4, 3, 15, 0, 0, 0, 0, 0] Reviewed: 22 States: [1, 7, 8, 84, 0, 0, 0, 0] (average 2.75)
Day 8. Due: 16∑ [1, 7, 8, 0, 0, 0, 0, 0] Reviewed: 16 States: [2, 2, 6, 90, 0, 0, 0, 0] (average 2.84)
Day 9. Due: 8∑ [2, 2, 4, 0, 0, 0, 0, 0] Reviewed: 0 States: [
@andymatuschak
andymatuschak / gdc-downloader.py
Created Dec 22, 2018 — forked from archagon/gdc-downloader.py
A quick and dirty script to download GDC Vault videos.
View gdc-downloader.py
# GDC Vault videos can't be watched on mobile devices and this is a very sad thing indeed!
# (Note: this has changed for GDC2013, which lets you watch raw MP4 streams. Kudos!)
# This script is designed to circumvent this by downloading the lecture and slideshow
# videos which can then be re-encoded into whatever format you wish. Obviously, you
# won't be able to do this without access to the Vault. This is strictly for the
# convenience of legitimate Vault users!
# Note: this code is rather flimsy and was written as fast as possible for my own personal use.
# The code only works for the most recent GDC Vault videos, since they all use the same player
# format. If the XML format used to run the player is changed (as it has in the past), the code
@andymatuschak
andymatuschak / States-v3.md
Last active Oct 14, 2020
A composable pattern for pure state machines with effects (draft v3)
View States-v3.md

A composable pattern for pure state machines with effects

State machines are everywhere in interactive systems, but they're rarely defined clearly and explicitly. Given some big blob of code including implicit state machines, which transitions are possible and under what conditions? What effects take place on what transitions?

There are existing design patterns for state machines, but all the patterns I've seen complect side effects with the structure of the state machine itself. Instances of these patterns are difficult to test without mocking, and they end up with more dependencies. Worse, the classic patterns compose poorly: hierarchical state machines are typically not straightforward extensions. The functional programming world has solutions, but they don't transpose neatly enough to be broadly usable in mainstream languages.

Here I present a composable pattern for pure state machiness with effects,

View gist:a40c4c699c0abdd704ce
// One note before we start: if the inhabitants of Value are a closed set,
// then making Value an enum is going to be a clearer model than using a
// protocol like this. I'm assuming you need to be able to retroactively add
// new members of Value.
// Can't use Equatable directly because of its Self requirement.
protocol HeteroEquatable {
func isEqualTo(value: HeteroEquatable) -> Bool
}
@andymatuschak
andymatuschak / MultiDirectionAdjudicatingScrollView.swift
Created Jan 26, 2015
Source for the Khan Academy app's unusual scrolling interactions
View MultiDirectionAdjudicatingScrollView.swift
//
// MultiDirectionAdjudicatingScrollView.swift
// Khan Academy
//
// Created by Andy Matuschak on 12/16/14.
// Copyright (c) 2014 Khan Academy. All rights reserved.
//
import UIKit
import UIKit.UIGestureRecognizerSubclass
@andymatuschak
andymatuschak / gist:2b311461caf740f5726f
Created Dec 28, 2014
A pragmatic and intentionally non-abstract solution to JSON decoding / initialization that doesn't require learning about five new operators.
View gist:2b311461caf740f5726f
struct User {
let id: Int
let name: String
let email: String?
}
extension User: JSONDecodable {
static func create(id: Int, name: String, email: String?) -> User {
return User(id: id, name: name, email: email)
}
@andymatuschak
andymatuschak / CollectionViewDataSource.swift
Last active Oct 27, 2020
Type-safe value-oriented collection view data source
View CollectionViewDataSource.swift
//
// CollectionViewDataSource.swift
// Khan Academy
//
// Created by Andy Matuschak on 10/14/14.
// Copyright (c) 2014 Khan Academy. All rights reserved.
//
import UIKit
View keybase.md

Keybase proof

I hereby claim:

  • I am andymatuschak on github.
  • I am andymatuschak (https://keybase.io/andymatuschak) on keybase.
  • I have a public key whose fingerprint is 289E CB4D BCC9 5D3A 71BD 6795 14CB 9F07 992C D348

To claim this, I am signing this object:

You can’t perform that action at this time.