15 // case x ~ y ~ z => ...  | 
    15 // case x ~ y ~ z => ...  | 
    16   | 
    16   | 
    17 case class ~[+A, +B](x: A, y: B)  | 
    17 case class ~[+A, +B](x: A, y: B)  | 
    18   | 
    18   | 
    19   | 
    19   | 
         | 
    20 trait IsSeq[I] { | 
         | 
    21   extension (i: I) def isEmpty: Boolean  | 
         | 
    22 }  | 
         | 
    23   | 
         | 
    24 given IsSeq[String] = _.isEmpty  | 
         | 
    25 given [I]: IsSeq[Seq[I]] = _.isEmpty  | 
         | 
    26   | 
         | 
    27   | 
    20 // parser combinators  | 
    28 // parser combinators  | 
    21 abstract class Parser[I, T] { p => | 
    29 abstract class Parser[I : IsSeq, T] { p => | 
    22   def parse(in: I): Set[(T, I)]    | 
    30   def parse(in: I): Set[(T, I)]    | 
    23   | 
    31   | 
    24   def parse_all(in: I)(using toSeq: I => Seq[?]) : Set[T] =  | 
    32   def parse_all(in: I) : Set[T] =  | 
    25     for ((hd, tl) <- parse(in);   | 
    33     for ((hd, tl) <- parse(in);   | 
    26         if toSeq(tl).isEmpty) yield hd  | 
    34         if tl.isEmpty) yield hd  | 
    27   | 
    35   | 
    28   // alternative parser  | 
    36   // alternative parser  | 
    29   def ||(q: => Parser[I, T]) = new Parser[I, T] { | 
    37   def ||(q: => Parser[I, T]) : Parser[I, T] = Parser[I, T] { | 
    30     def parse(in: I) = p.parse(in) ++ q.parse(in)  | 
    38     def parse(in: I) = p.parse(in) ++ q.parse(in)  | 
    31   }  | 
    39   }  | 
    32   | 
    40   | 
    33   // sequence parser  | 
    41   // sequence parser  | 
    34   def ~[S](q: => Parser[I, S]) = new Parser[I, T ~ S] { | 
    42   def ~[S](q: => Parser[I, S]) = new Parser[I, T ~ S] { |