Skip to content

Instantly share code, notes, and snippets.

@ssirowy
Last active March 20, 2022 23:07
Show Gist options
  • Save ssirowy/7de34e8f363fd984df7788fcd1ee38f6 to your computer and use it in GitHub Desktop.
Save ssirowy/7de34e8f363fd984df7788fcd1ee38f6 to your computer and use it in GitHub Desktop.
Wordle in FP-TS
import { ap, of, intersection } from 'fp-ts/Array'
import { Eq as StringEq } from 'fp-ts/string'
import { pipe } from 'fp-ts/function'
// Our word bank, shortened for brevity.
const wordBank = ['wince', 'hinge', 'movie', 'arbor' /** More */]
// Here is the function I need to write that can evaluate individual solutions. Note I have
// to write it in a curried form.
const word = (a: string) => (b: string) => (c: string) => `${a}i${b}${c}e`
// Here I am lifting "word" into the Array's applicative context, and applying an array functor (the letters)
// to each of its arguments using pipe. FP-TS can fully and correctly type this.
// Given how the Array applicative works, this function will generate all permutations of the letters passed in
// against the template defined in "word".
const allWords = (letters: string[]) => pipe(of(word), ap(letters), ap(letters), ap(letters))
// This function composes "allWords" and compares to a full word bank. The "intersection" function
// from FP-TS requires us to specify how to compare two things from each list, that's why I am passing
// in a function defined by FP-TS itself to compare two strings.
const allValidWords = (letters: string[]) => pipe(allWords(letters), intersection(StringEq)(wordBank))
// Take it for a spin. For above word bank, will return: ['wince', 'hinge']
allValidWords(['w', 't', 'y', 'g', 'h', 'j', 'k', 'c', 'n'])
@ssirowy
Copy link
Author

ssirowy commented Mar 20, 2022

Compare to the Ramda version here.

This solution is only one line longer than the Ramda solution, but much stronger typed! FP-TS doesn't include a point-free function for "lifting" a function like Ramda does due to Typescript typing issues, but hopefully line 16 isn't too difficult to parse.

I will write another example using a different applicative where the equivalent lifting line will essentially look the same.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment