-
-
Save sullyj3/11fb486a6c3917e7f8780bc1de1d0840 to your computer and use it in GitHub Desktop.
letterChar : Char -> Boolean | |
letterChar c = List.contains c <| toCharList "abcdefghijklmnopqrstuvwxyz" | |
groupAnswers : Text -> Map Char Nat | |
groupAnswers gr = | |
combine : Map Char Nat -> Char -> Map Char Nat | |
combine accMap c = | |
if letterChar c then | |
use Nat + | |
putWith (+) c 1 accMap | |
else accMap | |
List.foldLeft combine Map.empty <| toCharList gr | |
List.splitSubSeq : [a] -> [a] -> [[a]] | |
List.splitSubSeq lst sep = | |
go : [a] -> [a] -> [[a]] -> [[a]] | |
go lst' currSeq lists = | |
match stripPrefix sep lst' with | |
Some rest -> go rest [] (lists :+ currSeq) | |
None -> | |
match lst' with | |
x +: xs -> go xs (currSeq :+ x) lists | |
[] -> lists :+ currSeq | |
go lst [] [] | |
Text.splitSubSeq : Text -> Text -> [Text] | |
Text.splitSubSeq s sep = | |
List.map fromCharList (List.splitSubSeq (toCharList s) (toCharList sep)) | |
day6 : Text -> Nat | |
day6 input = | |
use List map | |
groups = Text.splitSubSeq input "\n\n" | |
theGroupAnswers = map groupAnswers groups | |
sum <| map Map.size theGroupAnswers | |
doDay6 : '{IO} () | |
doDay6 = | |
'let | |
f = openFile fp Read | |
contents = getText f | |
printLine (Nat.toText <| day6 contents) |
edit: Should note, this is all pre trying with the new runtime
Thanks very much for the suggestions!
I tried both Nat.inRange
and Char.inRange
, unfortunately it still took several seconds, so it seems like the main culprit is probably the splitSubSeq
functions.
Is it possible with the current primitives to implement Text.splitSubSeq directly without going through [Char]?
Good point! I realized I can implement Text.stripPrefix : Text -> Text -> Optional Text
in terms of those primitives:
Text.stripPrefix : Text -> Text -> Optional Text
Text.stripPrefix prefix text =
use Universal ==
prefixLen = Text.size prefix
p = Text.take prefixLen text
if p == prefix then Some (Text.drop prefixLen text) else None
I had a go at reimplementing Text.splitSubSeq
in terms of this. Here's my first attempt. You'll notice that while does use Text.stripPrefix
, it still uses uncons
and fromCharList
to accumulate each string.
Text.splitSubSeq : Text -> Text -> [Text]
Text.splitSubSeq text sep =
go : Text -> [Char] -> [Text] -> [Text]
go text' currSeq txts =
match Text.stripPrefix sep text' with
Some rest -> go rest [] (txts :+ fromCharList currSeq)
None ->
match uncons text' with
Some (c, rest) -> go rest (currSeq :+ c) txts
None -> txts :+ fromCharList currSeq
go text [] []
Expectedly, it turned out to still be fairly slow. I think in order to go faster I'd need something like break : Char -> Text -> (Text, Text)
(or (Char -> Bool) -> Text -> (Text, Text)
) in order to search for the first character of the separator.
> break 'a' "FOOaBAR"
("FOO", "aBAR")
As a data point, it seems like .base.Text.split
, a simpler version of this function, is implemented in terms of toCharList
split : Char -> Text -> [Text]
split separator text =
use Universal ==
go acc rest =
match indexOf separator rest with
None -> acc :+ fromCharList rest
Some n ->
use Nat +
go (acc :+ fromCharList (List.take n rest)) (List.drop (n + 1) rest)
if text == "" then [] else go [] (toCharList text)
Some comments:
letterChar
is super inefficient - it's going to be creating a boxed list of characters every time it's called, then doing linear search through that. Suggest just checking if theChar.toNat
is in the rangeChar.toNat ?a
throughChar.toNat ?z
.We could use some primitives for more text manipulation, converting to and from
[Char]
everywhere is going to be slow. Is it possible with the current primitives to implementText.splitSubSeq
directly without going through[Char]
?