Created
March 5, 2020 15:02
-
-
Save thoradam/7362431b78e3fe92bd28ae71b3167b4e to your computer and use it in GitHub Desktop.
Pure TypeScript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Did you know JavaScript has pure functions*? | |
// *: just add asterisks! | |
/** | |
* Describes a computation that requires `E` to produce an `A`. Has to be run | |
* to do anything. | |
* | |
* We could also do something like: | |
* `type Async<E,A> = Generator<void,Promise<A>,E>` | |
*/ | |
type IO<E,A> = Generator<void,A,E>; | |
/** | |
* The random effect 🎰 | |
*/ | |
interface Random { | |
random(): number | |
} | |
/** | |
* The logging effect 📝 | |
*/ | |
interface Log { | |
log(msg: any): void | |
} | |
function* random(): IO<Random, number> { | |
console.log('running random'); | |
// `yield` here fetches the `E` | |
return (yield).random(); | |
} | |
function* log(msg: any): IO<Log, void> { | |
console.log('running log'); | |
(yield).log(msg); | |
} | |
// Look Haskell, I'm pure! λ | |
{ | |
random(); | |
log('complete silence 😶') | |
} | |
function unsafeRun<E,A>(io: IO<E,A>, e: E): A { | |
let res; | |
do { | |
// Ignoring errors 🚨 | |
res = io.next(e) | |
} while (!res.done) | |
return res.value as A; | |
} | |
function* main() { | |
// We can use `yield*` like `<-` in Scala and Haskell | |
yield* log("i'm going to log something random"); | |
let rn = yield* random(); | |
yield* log(rn); | |
} | |
main() // Still pure 🚔 | |
// TypeScript somehow magically infers `E` to be `Log & Random` | |
// Here we could pass in mocks for testing 🧪 | |
unsafeRun(main(), { | |
log: (msg) => console.log(msg), | |
random: () => Math.random(), | |
}) |
@thoradam Did you continue any on this stuff? I'm still intrigued :) I just revisited fp-ts and io-ts and noticed he had somewhat better do-notation that I didn't find last time I looked:
https://gcanti.github.io/fp-ts/guides/do-notation.html
But there's something really cool here when stuck in ts…
@hedefalk No I didn’t take this further, not writing any TS anymore ^_^ Another thing I looked into at the time was overloading async/await, but unfortunately TS fixes it to Promise
. I had looked at the fp-ts do notation but I think it’s way too noisy :S
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I think I can definitely live with those yield*. Better than fp-ts pipe's!