请求增加use关键字

参考

通过use关键字将嵌套的回调函数铺平

type State[S, V] (S) -> (S, V)

fn State::map[S, X, Y](f : (X) -> Y , m : State[S, X]) -> State[S, Y] {
  fn res(state : S) -> (S, Y) {
    let State(m) = m
    let (newstate, value) = m(state)
    (newstate, f(value))
  }
  State(res)
}

fn State::new[S, T](val : T) -> State[S, T] {
  fn res(state : S) -> (S, T) {
    (state, val)
  }
  State(res)
}

fn State::bind[S, X, Y](m : State[S, X], f : (X) -> State[S, Y]) -> State[S, Y] {
  fn res(state : S) -> (S, Y) {
    let State(m) = m
    let (newstate, value) = m(state)
    let State(m) = f(value)
    m(newstate)
  }
  State(res)
}

fn mkPop[T]() -> State[List[T], T] {
  fn pop(stack : List[T]) -> (List[T], T) {
    match stack {
      Nil => abort("pop(): empty stack")
      Cons(elem, rest) => (rest, elem)
    }
  }
  State(pop)
}

fn mkPush[T]() -> (T) -> State[List[T], Unit] {
  fn push(elem : T) -> State[List[T], Unit] {
    State(fn (stack){(Cons(elem, stack), ())})
  }
  push
}

fn example() {
  let push = mkPush()
  let pop = mkPop()
  {
    State::bind(push(3), fn (__){
      State::bind(push(4), fn (__) {
        State::bind(pop, fn(four) {
          State::new("got \(four)")
        })
      })
    })
  }
  // 在引入use关键字后可改写为
  // {
  //   use State::bind(push(3))
  //   use State::bind(push(4))
  //   use four <- State::bind(pop)
  //   State::new("got \(four)")
  // }
  abort("")
}

感谢你的建议,我们之后会考虑对单子的一些操作添加语法糖。

至于你的例子,是不是可以写成

let State(m) = push(3)
  .bind(fn { _ => push(4) })
  .bind(fn { _ => pop })
  .bind(fn { four => State::new("got \(four)") })
3 个赞

Gleam目前的use相当于简化版的Elixir的with/1,后者除了可以预先绑定变量和做模式匹配外,还可使用else clause做异常处理:

opts = %{width: 10}
with {:ok, width} <- Map.fetch(opts, :width),
     {:ok, height} <- Map.fetch(opts, :height) do
  {:ok, width * height}
else
  :error ->
    {:error, :wrong_data}

  _other_error ->
    :unexpected_error
end

https://hexdocs.pm/elixir/Kernel.SpecialForms.html#with/1