我正在学习 Elm,让我困惑的一件事是“Json.Decode.succeed”。根据文档
succeed : a -> Decoder a
Ignore the JSON and produce a certain Elm value.
decodeString (succeed 42) "true" == Ok 42
decodeString (succeed 42) "[1,2,3]" == Ok 42
decodeString (succeed 42) "hello" == Err ...
Run Code Online (Sandbox Code Playgroud)
我理解这一点(尽管作为初学者,我还没有看到它的用途)。但该方法也用在解码管道中,因此:
somethingDecoder : Maybe Wookie -> Decoder Something
somethingDecoder maybeWookie =
Json.Decode.succeed Something
|> required "caterpillar" Caterpillar.decoder
|> required "author" (Author.decoder maybeWookie)
Run Code Online (Sandbox Code Playgroud)
这里发生了什么?也就是说,如果“succeed”忽略传递给它的 JSON,那么它如何用于读取 JSON 并将其转换为 Elm 值?任何线索表示赞赏!
首先,解码器管道的直觉是它的行为就像一个柯里化函数,其中逐一传递required和应用参数。optional预期所有内容(函数、其参数和返回值)都包含在Decoders 中。
举个例子:
succeed Something
|> required (succeed 42)
|> required (succeed "foo")
Run Code Online (Sandbox Code Playgroud)
相当于
succeed (Something 42 "foo")
Run Code Online (Sandbox Code Playgroud)
和
decodeString (succeed (Something 42 "foo")) whatever
Run Code Online (Sandbox Code Playgroud)
Ok (Something 42 "foo")只要whateverJSON 有效,就会返回。
当一切成功时,这只是一个非常复杂的函数调用。解码器更有趣的方面,以及我们首先使用它们的原因,在于错误路径。但由于这里感兴趣的是“成功”,因此我们将忽略它并节省大量时间、文本和脑细胞。只要知道,如果不考虑错误路径,这一切都会显得非常做作。
不管怎样,让我们尝试重新创建它,看看它是如何工作的。
除了管道运算符之外,管道的关键是函数Decode.map2。如果您尝试在不使用管道的情况下编写 JSON 解码器,那么您可能已经使用过它或其兄弟姐妹。map2我们可以使用这样的方法来实现上面的示例:
map2 Something
(succeed 42)
(succeed "foo")
Run Code Online (Sandbox Code Playgroud)
这将与上面的示例完全相同。但从用户的角度来看,这样做的问题是,如果我们需要添加另一个参数,我们也必须更改map2为map3. 而且也Something没有包含在解码器中,这很无聊。
无论如何,这是有用的,因为它使我们能够同时访问多个值,并且能够以我们想要的任何方式组合它们。我们可以使用它来调用 a 中的函数,Decoder并在 a 中使用参数Decoder,并将结果也包装在 a 中Decoder:
map2 (\f x -> f x)
(succeed String.fromInt)
(succeed 42)
Run Code Online (Sandbox Code Playgroud)
map不幸的是,如果我们需要更多参数,这仍然存在需要更改函数的问题。如果有一种方法可以一次将参数应用到一个函数上就好了……就像我们有柯里化和部分应用一样。既然我们现在有办法调用解码器中包装的函数,那么如果我们返回部分应用的函数并稍后应用剩余的参数会怎么样?
map2 (\f x -> f x)
(succeed Something)
(succeed 42)
Run Code Online (Sandbox Code Playgroud)
将返回 a Decoder (string -> Something),所以现在我们只需冲洗并重复这个和最后一个参数:
map2 (\f x -> f x)
(map2 (\f x -> f x)
(succeed Something)
(succeed 42))
(succeed "")
Run Code Online (Sandbox Code Playgroud)
瞧,我们现在重新创建了 JSON 解码管道!虽然表面上看起来可能不太像。
map2最后的技巧是与管道运算符一起使用。管道本质上定义为\x f -> f x。看看这与我们一直使用的函数有多相似?唯一的区别是参数交换了,所以我们也需要交换传递参数的顺序:
map2 (|>)
(succeed "")
(map2 (|>)
(succeed 42)
(succeed Something))
Run Code Online (Sandbox Code Playgroud)
然后我们可以再次使用管道运算符来达到最终的形式
succeed Something
|> map2 (|>)
(succeed 42)
|> map2 (|>)
(succeed "")
Run Code Online (Sandbox Code Playgroud)
现在应该很明显,这required只是 的别名map2 (|>)。
这就是全部!
| 归档时间: |
|
| 查看次数: |
817 次 |
| 最近记录: |