Skip to content

Instantly share code, notes, and snippets.

@lazamar
Last active August 29, 2023 20:32
Show Gist options
  • Save lazamar/305e8808f8975258f6acea4d20fd3405 to your computer and use it in GitHub Desktop.
Save lazamar/305e8808f8975258f6acea4d20fd3405 to your computer and use it in GitHub Desktop.
Solution to nested-map-reduce-traversal challenge.
{- This is a solution to https://github.com/josevalim/nested-map-reduce-traversal
without using explicit accumulators.
You can run it with:
$ ghc Main.hs && ./Main
Which outputs:
Numbered 0 ("One",[Numbered 0 "A",Numbered 1 "B"])
Numbered 1 ("Two",[Numbered 2 "C",Numbered 3 "D",Numbered 4 "E"])
Numbered 2 ("Three",[Numbered 0 "F",Numbered 1 "G"])
Numbered 3 ("Four",[])
Numbered 4 ("Five",[Numbered 0 "H"])
-}
module Main where
import Data.List (tails)
type SectionTitle = String
type Lesson = String
data Section = Section
{ title :: SectionTitle
, reset_lesson_position :: Bool
, lessons :: [Lesson]
}
deriving Show
data Numbered a = Numbered Int a
deriving Show
type Result = (SectionTitle, [Numbered Lesson])
main = putStrLn $ unlines $ map show $
numberIt
[ Section "One" True ["A", "B"]
, Section "Two" False ["C", "D", "E"]
, Section "Three" True ["F", "G"]
, Section "Four" False []
, Section "Five" True ["H"]
]
numberIt :: [Section] -> [Numbered Result]
numberIt = numbered . concatMap numberLessons . spans
where
-- stretches where lessons should be sequentially numbered
spans :: [Section] -> [[Section]]
spans sections =
map (\(x:xs) -> x : takeWhile (not . reset_lesson_position) xs) $
filter (reset_lesson_position . head) $
filter (not . null) $
tails sections
numberLessons :: [Section] -> [Result]
numberLessons sections = map groupBy (map title sections)
where
groupBy title = (title, map snd $ filter ((== title) . fst) annotated)
annotated :: [(SectionTitle, Numbered Lesson)]
annotated = uncurry zip $ fmap numbered $ unzip $ concatMap annotate sections
annotate :: Section -> [(SectionTitle, Lesson)]
annotate (Section title _ lessons) = map (title,) lessons
numbered :: [a] -> [Numbered a]
numbered xs = zipWith Numbered [0..] xs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment