Skip to content

Instantly share code, notes, and snippets.

@pete-murphy
Last active November 28, 2020 14:57
Show Gist options
  • Save pete-murphy/51c2d975a51ca280b3c6043be0662c20 to your computer and use it in GitHub Desktop.
Save pete-murphy/51c2d975a51ca280b3c6043be0662c20 to your computer and use it in GitHub Desktop.
import qualified Control.Monad as Monad
import Control.Monad.Trans.State (State)
import qualified Control.Monad.Trans.State as State
import Data.Function ((&))
import Control.Arrow ((&&&))
data Node = Node {children :: [Node], metadata :: [Int]}
allMetadata :: Node -> [Int]
allMetadata node = metadata node ++ concatMap allMetadata (children node)
getInt :: State [Int] Int
getInt = do
-- first : rest <- State.get
-- ^^ The above is valid if using GHC < 8.8.1, but recent versions will
-- complain about missing 'MonadFail' instance for 'Identity' ('State' is
-- defined as 'StateT Identity', and the pattern match might fail. If you want
-- to dig further into the weeds, see:
-- https://hackage.haskell.org/package/base-4.14.0.0/docs/Control-Monad-Fail.html#t:MonadFail)
(first, rest) <- State.gets (head &&& tail)
State.put rest
pure first
getNode :: State [Int] Node
getNode = do
n <- getInt
m <- getInt
Node <$> Monad.replicateM n getNode <*> Monad.replicateM m getInt
main :: IO ()
main = do
input <- readFile "input"
input
& words
& map read
& State.evalState getNode
& allMetadata
& sum
& print
import fs from "fs"
import * as St from "fp-ts/lib/State"
import State = St.State
import * as A from "fp-ts/lib/Array"
import { pipe } from "fp-ts/lib/pipeable"
import { sequenceS, sequenceT } from "fp-ts/lib/Apply"
import { fold, monoidSum } from "fp-ts/lib/Monoid"
interface Node {
children: readonly Node[]
metadata: readonly number[]
}
const allMetadata: (node: Node) => number[] = node => [
...node.metadata,
...node.children.flatMap(allMetadata),
]
const getInt: State<number[], number> = pipe(
St.get<number[]>(),
St.chain(([first, ...rest]) =>
pipe(
St.of<number[], number>(first),
St.chainFirst(() => St.put(rest))
)
)
)
const getNode: State<number[], Node> = pipe(
sequenceT(St.state)(getInt, getInt),
St.chain(
([n, m]): State<number[], Node> =>
sequenceS(St.state)({
children: St.sequenceArray(A.replicate(n, getNode)),
metadata: St.sequenceArray(A.replicate(m, getInt)),
})
)
)
const words = (str: string) => str.split(/\s/)
const main = () =>
pipe(
fs.readFileSync("input", "utf8"),
words,
A.map(Number),
ns => St.evaluate(ns)(getNode),
allMetadata,
fold(monoidSum),
console.log
)
main()
@pete-murphy
Copy link
Author

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