Skip to content

Instantly share code, notes, and snippets.

@sullyj3
Last active December 8, 2020 08:00
Show Gist options
  • Save sullyj3/11fb486a6c3917e7f8780bc1de1d0840 to your computer and use it in GitHub Desktop.
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)
@sullyj3
Copy link
Author

sullyj3 commented Dec 8, 2020

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")

@sullyj3
Copy link
Author

sullyj3 commented Dec 8, 2020

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)

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