我试图理解Elm中定义类型和模式匹配的所有不同方式。
在寻找可学习的代码时,我发现了纯Elm中的JSON解码器实现。可以找到代码here和文章系列here。
我无法理解字段函数中使用的样式:
type Value
= Jnull
| Jobject (Dict String Value)
type Decoder a
= Decoder (Value -> Result String a)
decodeValue : Decoder a -> Value -> Result String a
decodeValue (Decoder attemptToDecode) value =
attemptToDecode value
field : String -> Decoder a -> Decoder a
field key (Decoder parameterAttempt) =
let
decodeKey object =
Dict.get key object
|> Result.fromMaybe "couldn't find key"
|> Result.andThen parameterAttempt
attemptToDecode value =
case value of
Jobject foundIt ->
decodeKey foundIt
_ ->
Err "not an object"
in
Decoder attemptToDecode
为该函数编写的测试如下:
test "decodes a field" <|
\_ ->
Jobject (Dict.singleton "nested" (Jnumber 5.0))
|> decodeValue (field "nested" int)
|> Expect.equal (Ok 5)
我不了解租借的内容。为什么会有这样的分配?如何评估代码?
Dict.get关键对象
处理并“绑定”到?
decodeKey对象= ...
attemptToDecode值= ...
从根本上讲,我正在尝试了解let中发生的情况,以便它为 Decoder tryToDecode 返回“有用”的内容。另外,有没有更好的方式表达意图?
先谢谢您!
答案 0 :(得分:2)
我认为@ zh5在以下方面有道理:
另一方面,即使不是总是很有用,尝试出于好奇也能理解是一件好事,所以我会尝试提供帮助。
这是field
(我想)的意图:
在
Decoder
中给我“逻辑” ,我可以用它来解码字段 给我一个名字我将从您的Decoder
中删除“逻辑” , 在其上方放置一些“额外逻辑” 以查找 JSON对象中的字段,我将把这个结合起来 新Decoder
中的逻辑。
因此,“额外逻辑”在上面的代码中分为两部分:
attemptToDecode
捕获用于确保解码的内容是JSON对象的逻辑。此JSON对象的值表示为字典,该字典被提取并传递给第二部分。 decodeKey
捕获了逻辑的另一半。有了字典形式的JSON对象的内容后,现在我们应该找到该字段,并尝试使用Decoder
中提供的“逻辑” 对其进行解码。此逻辑从解码器解构,并在代码中称为parameterAttempt
。 现在,attemptToDecode
引用了decodeKey
,然后引用了parameterAttempt
(用于对该字段进行解码的原始逻辑),因此我们可以说attemptToDecode
捕获从JSON对象解码字段所需的全部逻辑。因此,此时,所有要做的就是将逻辑包装回Decoder
中,这正是代码所说明的:
Decoder attemptToDecode
当然,您肯定是对的,解码器中捕获的逻辑是以函数形式捕获的,当这些函数相互引用时,它们的类型签名必须最后匹配。
答案 1 :(得分:0)
Decoder类型定义为:
void insert_node(struct node * root, struct node * node, unsigned mask, unsigned path)
{
while ((mask >> 1) != 1) {
root = mask & path? root->right: root->left;
}
if (mask & path) {
assert (root->right == NULL);
root->right = node;
} else {
assert (root->left == NULL);
root->left = node;
}
}
void fill_level_k(struct node * root, unsigned k)
{
unsigned slots = 1 << k;
for (unsigned slot = 0; slot < slots; slot++) {
struct node * node = generate_new_node();
insert_node(root, node, slots, slot);
}
}
只有一个数据构造函数带有一个参数。这意味着要构建解码器,我们需要一个函数,该函数需要一个Value并返回结果字符串a:
type Decoder a
= Decoder (Value -> Result String a)
let 中的分配是构建函数,并用作构建块。读取它们的类型定义可以使事情更清楚。
f: Value -> Result String a -> Decoder a
attemptToDecode 使用 decodeKey 并可以这样做,因为它们都返回
结果字符串a
对此表示任何反馈。