1

我正在关注这篇关于 catamorphism 的文章,我正在尝试为这样的递归数据类型定义折叠函数

type Node anyType
    = Leaf Id (Maybe anyType)
    | Tree Id (List (Node anyType))

我写的是这样的:

foldTree fLeaf fTree acc node =
let
    recurse =
        foldTree fLeaf fTree
in
case node of
    Leaf id v -> 
        let
            newAcc = fLeaf acc (id, v)
        in
            newAcc

    Tree id l ->
        let
            newAcc = fTree acc id
            
                
        in
            l |> List.foldl recurse newAcc 

如果我不推断foldTree函数编译的类型,但它似乎不可用:

collectIds node = 
let
    fLeaf acc (id,v) = id :: acc
    fTree acc id = id :: acc
in

foldTree fLeaf fTree [] node

抛出以下内容:

TYPE MISMATCH - The 1st argument to `foldTree` is not what I expect:

173|     foldTree fLeaf fTree [] node
              #^^^^^#
This `fLeaf` value is a:

#List a# -> ( a, b ) -> #List a#

But `foldTree` needs the 1st argument to be:

#Node anyType# -> ( Id, Maybe anyType ) -> #Node anyType#

自动推断其类型foldTree使其不可编译并抛出以下内容:

-- Auto Inferred
foldTree : (c -> (Id, Maybe anyType) -> a) -> (c -> Id -> b) -> c -> Node anyType -> d

TYPE MISMATCH - Something is off with the 1st branch of this `case` expression:

126|                 newAcc
                     #^^^^^^#
This `newAcc` value is a:
#a#

But the type annotation on `foldTree` says it should be:

    #d#

#Hint#: Your type annotation uses `a` and `d` as separate type variables. Your
code seems to be saying they are the same though. Maybe they should be the same
in your type annotation? Maybe your code uses them in a weird way?

如果我尝试按照提示进行操作,仍然无法编译

foldTree : (c -> (Id, Maybe anyType) -> a) -> (c -> Id -> b) -> c -> Node anyType -> a

TYPE MISMATCH - This function cannot handle the argument sent through the (|>) pipe:

134|                 l |> List.foldl recurse newAcc 
                          #^^^^^^^^^^^^^^^^^^^^^^^^^#
The argument is:

    List #(Node anyType)#

But (|>) is piping it to a function that expects:

    List #c#

#Hint#: Your type annotation uses type variable `c` which means ANY type of value
can flow through, but your code is saying it specifically wants a `Node` value.
Maybe change your type annotation to be more specific? Maybe change the code to
be more general?

Read <https://elm-lang.org/0.19.1/type-annotations> for more advice!Elm
TYPE MISMATCH - The 1st argument to `foldl` is not what I expect:

134|                 l |> List.foldl recurse newAcc 
                                     #^^^^^^^#
This `recurse` value is a:

    c -> Node anyType -> #a#

But `foldl` needs the 1st argument to be:

    c -> Node anyType -> #Node anyType#

#Hint#: Your type annotation uses type variable `a` which means ANY type of value
can flow through, but your code is saying it specifically wants a `Node` value.
Maybe change your type annotation to be more specific? Maybe change the code to
be more general?

我被困住了。准确地遵循文章上的类型似乎也不起作用。我知道文章中的代码是 F#,我正在研究 Elm,但我认为在这种情况下,它应该是 100% 可翻译的。

我哪里错了?

提前致谢!

4

1 回答 1

4

您已将论点翻转为List.foldl. fold 函数首先获取值,然后是累加器,而您的recurse函数首先获取累加器,然后是值。

对此的简单解决方法是扩展递归函数并在将其传递给时翻转参数foldTree

recurse v a = foldTree fLeaf fTree a v

此外,有趣的是,注释的类型recurse将使其编译,但显然会产生错误的结果。我没有进一步了解原因,因为它是错误的,但是您应该从中吸取的教训是始终注释您的顶级功能。这将为您提供更好的错误消息,但也可以防止您的代码意外编译但产生错误的结果。

于 2022-02-07T09:45:29.973 回答