Fork channel

Create a new channel as a copy of main.

Rename channel

Rename main to:

Delete channel

Delete main? This cannot be undone.

ingredients.hs
import Control.Arrow
import Data.Function
import Data.List
import Data.Map.Merge.Strict hiding (merge)
import qualified Data.Map.Merge.Strict as MM
import qualified Data.Map.Strict as M
import Data.Maybe
import qualified Data.Set as S

parse :: [String] -> M.Map String (S.Set String)
parse = foldr combine M.empty . map (go S.empty . words)
  where
    go _ [] = undefined
    go ingredients (s : ss) =
      case s of
        "(contains" ->
          -- every word here will have a trailing char, be it ',' or ')'
          let allergens = map init ss
           in foldr (flip M.insert ingredients) M.empty allergens
        _ -> go (S.insert s ingredients) ss

    combine =
      MM.merge
        preserveMissing
        preserveMissing
        (zipWithMatched (\_ -> S.intersection))

solveOne :: String -> Int
solveOne =
  length
    . uncurry filter
    . first potentialAllergen
    . (parse &&& allIngredients)
    . lines
  where
    allIngredients = concat . map (words . takeWhile (/= '('))
    potentialAllergen = flip S.notMember . M.foldr' S.union S.empty

solveConstraints :: M.Map String (S.Set String) -> M.Map String String
solveConstraints ms = go ms id (\_ -> undefined)
  where
    go ms s k =
      if M.null ms
        then s M.empty
        else
          let (allergen, candidates) =
                minimumBy (compare `on` (S.size . snd)) $ M.assocs ms
           in case S.minView candidates of
                Nothing -> k ()
                Just (guess, others) ->
                  let ms' = M.map (S.delete guess) $ M.delete allergen ms
                   in go
                        ms'
                        (s . M.insert allergen guess)
                        ( \() ->
                            let ms'' = M.insert allergen others
                             in go ms' s k
                        )

solveTwo :: String -> String
solveTwo =
  filter (not . (`elem` "[ \"]"))
    . show
    . M.elems
    . solveConstraints
    . parse
    . lines