Here is my solution for day 5. This one was easy. Just merging ranges in part two. Litle trick is to order the ranges first.
Solution
namespaceDay05-- PARSERinductiveParseError|invalidNumberInRange(ab:String)|invalidNumber(n:String)|invalidRangeOrd(lh:Nat)|invalidRangeFormat(s:String)|invalidInputFormat(n:Nat)instance:ToStringParseErrorwheretoString|.invalidNumberInRangeab=>s!"Invalid number in range: '{a}-{b}'"|.invalidNumbern=>s!"Invalid number: '{n}'"|.invalidRangeOrdlh=>s!"Invalid range order: '{l}-{h}', expected lower ≤ higher"|.invalidRangeFormats=>s!"Invalid range format: '{s}', expected '<nat>-<nat>'"|.invalidInputFormatn=>s!"Invalid input format, expected 2 sections but got {n}"instance:CoeParseErrorIO.Errorwherecoee:=IO.userError(toStringe)instance:MonadLift(ExceptParseError)IOwheremonadLift|.oka=>returna|.errore=>throw↑eabbrevRange:=Nat×NatdefparseRange(s:String):ExceptParseErrorRange:=doletparts:=s.splitOn"-"matchpartswith|[a,b]=>match(a.toNat?,b.toNat?)with|(somena,somenb)=>ifna≤nbthenreturn(na,nb)elsethrow<|.invalidRangeOrdnanb|_=>throw<|.invalidNumberInRangeab|_=>throw<|.invalidRangeFormatsdefparseRanges(input:String):ExceptParseError(ListRange):=input.splitOn"\n"|>.mapMparseRangedefparseId(idStr:String):ExceptParseErrorNat:=matchidStr.toNat?with|someid=>returnid|none=>throw<|.invalidNumberidStrdefparseIds(input:String):ExceptParseError(ListNat):=input.splitOn"\n"|>.mapMparseIddefparseInput(input:String):IO((ListRange)×ListNat):=doletlines:=input.splitOn"\n\n"matchlineswith|[rangesSection,idSection]=>doletranges←parseRangesrangesSectionletids←parseIdsidSectionreturn(ranges,ids)|_=>throw<|(ParseError.invalidInputFormatlines.length:IO.Error)defreadInput:IOString:=doIO.FS.readFile"LeanAoc/day05/input.txt"-- COMMONdefRange.size(r:Range):Nat:=r.2-r.1+1instanceinstNatInRange:MembershipNatRangewherememrangeid:=id≥range.1∧id≤range.2instanceinstDecidableNatInRange(id:Nat)(range:Range):Decidable(id∈range):=inferInstanceAs(Decidable(id≥range.1∧id≤range.2))-- PART 1deffreshIngredients(ranges:ListRange)(ids:ListNat):ListNat:=ids.filterfunid=>ranges.any(id∈·)deffreshIngredientsCount(ranges:ListRange)(ids:ListNat):Nat:=freshIngredientsrangesids|>.length/--info: 3-/#guard_msgsin#evaldoletinput:="3-5\n10-14\n16-20\n12-18\n\n1\n5\n8\n11\n17\n32"let(ranges,ids):=←parseInputinputreturnfreshIngredientsCountrangesids#evaldoletinput:=←readInputlet(ranges,ids):=←parseInputinputreturnfreshIngredientsCountrangesids-- PART 2defmergeOrderedRanges(r1r2:Range):OptionRange:=ifr2.1≤r1.2thensome(r1.1,maxr1.2r2.2)elsenonedefmergeOverlappingRanges(ranges:ListRange):ListRange:=ranges.mergeSort(funab=>a.1≤b.1)|>.foldl(funaccr=>matchaccwith|[]=>[r]|h::t=>matchmergeOrderedRangeshrwith|somemerged=>merged::t|none=>r::acc)[]defcountFreshIngredientsRanges(ranges:ListRange):Nat:=mergeOverlappingRangesranges|>.mapRange.size|>.sum/--info: 14-/#guard_msgsin#evaldoletinput:="3-5\n10-14\n16-20\n12-18\n\n1\n5\n8\n11\n17\n32"let(ranges,_):=←parseInputinputreturncountFreshIngredientsRangesranges#evaldoletinput:=←readInputlet(ranges,_):=←parseInputinputreturncountFreshIngredientsRangesrangesendDay05