Skip to content

Instantly share code, notes, and snippets.

@GeoffChurch
Last active March 7, 2021 16:28
Show Gist options
  • Save GeoffChurch/47c8d0a585cdb4c3752837e73ed03fb3 to your computer and use it in GitHub Desktop.
Save GeoffChurch/47c8d0a585cdb4c3752837e73ed03fb3 to your computer and use it in GitHub Desktop.
"Diagonalized" version of <*> for lists, which reaches every finitely reachable application
ap :: [a -> b] -> [a] -> [b]
ap fs xs = go1 ([], fs) ([], xs)
where
go1 (fs, []) (_, xs) = [f x | x <- xs, f <- fs] -- No more fs: roundrobin seen fs on unseen xs.
go1 fs@(_, f : _) xs@(seenxs, _) = [f x | x <- seenxs] ++ go2 (step fs) xs -- Apply next f to seen xs and recur.
go2 (_, fs) (xs, []) = [f x | f <- fs, x <- xs] -- No more xs: roundrobin seen xs on unseen fs.
go2 fs@(seenfs, _) xs@(_, x : _) = [f x | f <- seenfs] ++ go1 fs (step xs) -- Apply seen fs to next x and recur.
step (seen, cur : unseen) = (cur : seen, unseen) -- Mark current element as seen.
-- E.g. to generate all triples
-- pure (,,) `ap` [1..] `ap` [1..] `ap` [1..]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment