anchor.diff:         | '!'::_::rest -> parseInner rest
          | '>'::rest -> Some((), rest)
          | _::rest -> parseInner rest
  -
      function
      | '<'::inner -> parseInner inner
      | _ -> None
  
positive.code:         n + Seq.sumBy (innerScore (n+1)) groups
      innerScore 1 g
  
  let readInput file = File.ReadAllText(file).Trim() |> List.ofSeq
  
  let solve1 input =
      let g = input |> parseGroup
      match g with
      | Some (group, _) -> score group
      | None -> 0
  
  [<EntryPoint>]
  let main _ = 
      let input = readInput "input.txt"
  
      test parseGroupOrGarbage [
          ("{}" |> List.ofSeq), Some (Choice1Of2 (Group []), []);
          ("{{}}" |> List.ofSeq), Some (Choice1Of2 (Group [Group []]), []);
          ("{{},{}}" |> List.ofSeq), Some (Choice1Of2 (Group [Group []; Group []]), []);
          ("{{{}},{}}" |> List.ofSeq), Some (Choice1Of2 (Group [Group [Group []]; Group []]), []);
      ]
  
      test score [
  
negative.code:     let result1 = timeIt (fun () -> solve1 input)
      printfn "Result 1: %A" result1
  
      printfn "--- Tests ---\n"
      test solve2 [
          ("{}", 0);
          ("<>", 0);
          ("{<random characters>}", 17);
          ("<<<<>", 3);
          ("<!!>", 0);
      ]
  
      let result2 = timeIt (fun () -> solve2 input)
      printfn "Result 2: %A" result2
  
      Console.ReadLine() |> ignore
      0 // return an integer exit code
  