Return in while loop is not expected behaviour

playground

type ParsedValue[V] Result[(V, String), String]

struct Lexer[V] {
  parse: (String) -> ParsedValue[V]
}

fn Lexer::and[V1, V2](self: Lexer[V1], lexer2: Lexer[V2]) -> Lexer[(V1, V2)] {
  fn parse(str: String) -> ParsedValue[(V1, V2)] {
    let r1 = (self.parse)(str)
    match r1.0 {
      Ok((curr, rest)) => {
        let r2 = (lexer2.parse)(rest)
        match r2.0 {
          Err(err) => ParsedValue(Err(err))
          Ok((curr2, rest2)) => ParsedValue(Ok(((curr, curr2), rest2)))
        }
      }
      Err(err) => ParsedValue(Err(err))
    }
  }

  {
    parse,
  }

}

fn Lexer::or[V](self: Lexer[V], lexer2: Lexer[V]) -> Lexer[V] {
  fn parse(str: String) -> ParsedValue[V] {
    let r1 = (self.parse)(str)
    match r1.0 {
      Ok(_) => r1
      Err(_) => {
        let r2 = (lexer2.parse)(str)
        match r2.0 {
          Ok(_) => r2
          Err(_) => r2
        }
      }
    }
  }
  {
    parse,
  }
}

fn Lexer::map[V, V2](self: Lexer[V], f: (V) -> V2) -> Lexer[V2] {
  fn parse(str: String) -> ParsedValue[V2] {
    let r1 = (self.parse)(str)
    match r1 {
      ParsedValue(Ok((curr, rest))) => ParsedValue(Ok((f(curr), rest)))
      ParsedValue(Err(err)) => ParsedValue(Err(err))
    }
  }
  {
    parse,
  }
}

fn Lexer::many[V](self: Lexer[V]) -> Lexer[List[V]] {
  fn parse(str: String) -> ParsedValue[List[V]] {
    let mut result: List[V] = List::Nil
    let mut rest = str
    while true {
      if rest.length() == 0 {
        return ParsedValue(Ok((result, rest)))
      }
      match (self.parse)(rest) {
        ParsedValue(Ok((curr, rest_))) => {
          result = List::Cons(curr, result)
          rest = rest_
          continue
        }
        ParsedValue(Err(err)) => {
          return ParsedValue(Err(err))
        }
      }
    }
    // ParsedValue(Ok((result, rest)))
    abort("unimplemented")
  }
  {
    parse,
  }
}

fn init {
  
}

In the function Lexer::many, the while loop will break and return when the rest string is empty, while the type of while loop expression is Unit which cause compiler error of type mismatch.
Expected behaviour: the type of while loop expression should not be Unit when it has return statement in the body.

Hi there! Currently the type of a while-loop is always Unit. There is no way to infer the type of a while-loop based on how return is used inside the while-loop. We will enhance the while-loop so that it can yield a value at the end in the near future. For your purpose, I would recommend you use the functional loop:

  fn parse(str: String) -> ParsedValue[List[V]] {
    loop str, List::Nil {
      "", acc => ParsedValue(Ok(acc, ""))
      rest, acc => {
        match (self.parse)(rest) {
          ParsedValue(Ok(curr, rest_)) => continue rest_, List::Cons(curr, acc)
          ParsedValue(Err(err)) => ParsedValue(Err(err))
        }
      }
    }
  }

You can find relevant document here: MoonBit | MoonBit

1 Like