Skip to content

Instantly share code, notes, and snippets.

@aaronlevin
Last active June 24, 2016 16:57
Show Gist options
  • Save aaronlevin/d798df06bd303f767a81 to your computer and use it in GitHub Desktop.
Save aaronlevin/d798df06bd303f767a81 to your computer and use it in GitHub Desktop.
Adventures in Point-Free, Arrowized Absurdity
-- | check for parens in a string, exiting early if the left paren count is -1. Fully point-free and
-- arrow-fied
-- It works as follows:
-- 1. use a monadic fold (foldM) with the Either monad to exit early
-- 2. take a list of methods that test if the count is -1, or the paren is '(', or the paren is ')'
-- 3. zip the list with another list that looks at the booleans and decides what functions they should
-- result in. if there are no parens, the functions just add 0 to the count
-- 4. sequence the monad actions (this will exit early if there is a Left present)
-- 5. fold over the functions in the Right branch with function composition
-- 6. at this piont we just want to apply the the resulting function in the Right branch to the current
-- count. this was *really* hard in point-free for, hence the &&& fst >>> second (fmap . flip ($))
-- tomfoolery. it took me an embarrassingly long time to figure this out :(
-- 7. when the foldM is finished, we have `False` if there is a `Left` and we check that the left paren
-- count is `0` on the right.
--
-- >>> checkParens "hello"
-- True
-- >>> checkParens "he(llo"
-- False
-- >>> checkParens "he(ll)o"
-- True
-- >>> checkParens "h)e(ll)o"
-- False
checkParens :: String -> Bool
checkParens = either (const False) (== 0) . foldM go 0
where
go = curry $ ( sequence [(== -1) . fst, (== '(') . snd, (== ')') . snd]
>>> zipWith (bool . Right $ (+ 0)) [Left (), Right (+ 1), Right (flip (-) 1)]
>>> sequence
>>> (<$>) (foldl (.) id)
)
&&& fst
>>> second (fmap . flip ($))
>>> swap
>>> app
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment