如何在Elm中结合结果和状态?

Joo*_*zan 5 monads haskell monad-transformers elm

我为榆树缺少单子而苦苦挣扎。实现Elm状态monad的库(http://package.elm-lang.org/packages/folkertdev/elm-state/latest/State)对我有很大帮助。

问题是,当我只想分别使用Result和State类型时,现在遇到了交替嵌套的Result和State类型的情况。

我尝试编写具有以下签名的函数,但似乎不可能,因为内部Result仅在评估外部State后才知道。

join : Result a (State s (Result a (State s x))) -> Result a (State s x)
Run Code Online (Sandbox Code Playgroud)

如果我将Result放入返回值中的State中,则可能会起作用,但是如果外部Result为,那会生成一个哑状态Err

我认为正确的想法是做出既是结果又是状态的东西。熟悉Haskell monad变压器的人可以解释他们如何解决此类问题或提出替代解决方案吗?

这是一个出现问题的地方的粗略版本:

  generateConstraints environment value
  |> Result.map (State.map (\(value, valueC) ->
    Result.map
      (State.map2 (\this (body, bodyC) ->
        ( this
        , valueC ++ bodyC ++ [(this, body)]
        ))
      freshTypevar)
      (generateConstraints (extend environment name value) body))
  )
Run Code Online (Sandbox Code Playgroud)

Joo*_*zan 2

我最终写了一个兼具两者的单子。我必须牺牲在状态被触及之前失败的能力,因为我需要能够在之后失败。

type alias Infer a = State Int (Result String a)

infer : a -> Infer a
infer x =
  State.state (Ok x)

map : (a -> value) -> Infer a -> Infer value
map f x =
  State.map (Result.map f) x

andThen : (a -> Infer b) -> Infer a -> Infer b
andThen f x =
  State.andThen
    (\r -> case r of
      Ok v -> f v
      Err e -> State.state <| Err e
    )
    x

andMap : Infer y -> Infer (y -> z) -> Infer z
andMap y =
  andThen (\g -> map g y)

map2 : (a -> b -> c) -> Infer a -> Infer b -> Infer c
map2 f x y =
  map f x
  |> andMap y

map3 : (a -> b -> c -> d) -> Infer a -> Infer b -> Infer c -> Infer d
map3 f a b c =
  map2 f a b
  |> andMap c

map4 : (a -> b -> c -> d -> e) -> Infer a -> Infer b -> Infer c -> Infer d -> Infer e
map4 f a b c d =
  map3 f a b c
  |> andMap d
Run Code Online (Sandbox Code Playgroud)