简体   繁体   English

Haskell - 将列表转换为递归数据结构

[英]Haskell - Translate a list to a recursive data structure

I found this problem in a Haskell textbook.我在 Haskell 教科书中发现了这个问题。 Given a recursive data structure:给定递归数据结构:

data Foo = A Foo Foo | B Int Foo | C Int

create a function:创建一个函数:

createFooFromList :: [Int] -> Foo -> Foo

that takes in a list and a Foo , applies the list to the Foo , and returns the new Foo .它接受一个列表和一个Foo ,将该列表应用于Foo ,并返回新的Foo

What "applying" means is best described using an example.使用示例最好地描述“应用”的含义。

Say we have a Foo that is defined as B 0 (B 1 (A (B 0 (C 1)) (B 1 (C 1)))) and we have to apply the list [0,0,1,0,2,0] to this Foo .说,我们有一个Foo被定义为B 0 (B 1 (A (B 0 (C 1)) (B 1 (C 1))))我们必须应用列表[0,0,1,0,2,0]到这个Foo To do this, simply take each integer in the given sequence and replace integers in the Foo structure in order with these integers in the sequence.为此,只需取给定序列中的每个整数,并按顺序用序列中的这些整数替换Foo结构中的整数。

So for the above example, our output would be B 0 (B 0 (A (B 1 (C 0)) (B 2 (C 0))))所以对于上面的例子,我们的输出将是B 0 (B 0 (A (B 1 (C 0)) (B 2 (C 0))))

So far, I have created a function that applies the list to the B and C structures.到目前为止,我已经创建了一个将列表应用于BC结构的函数。 C is trivial, and B is also easy as I simply set the head of the list to the Int parameter of B , and recursively apply the rest of the list to the Foo part of B . C很简单,而B也很简单,因为我只需将列表的头部设置为BInt参数,然后递归地将列表的其余部分应用于BFoo部分。 However I am unsure as to how to deal with A .但是我不确定如何处理A

Here is a hint:这是一个提示:

I would start by writing an auxiliary function, which takes the [Int] and Foo arguments, and returns not just the output Foo but an additional [Int] representing the numbers in the input list which have not been used, yet.我将首先编写一个辅助函数,它接受[Int]Foo参数,不仅返回输出Foo ,还返回一个额外的[Int]表示输入列表中尚未使用的数字。 Hence, the resulting output type can be a pair.因此,结果输出类型可以是一对。

The intuition here is that this auxiliary function does not assume that the input [Int] list contains the right amount of numbers for the Foo input, but allows more Int s to be present, and returns the ones in excess.这里的直觉是这个辅助函数不假设输入[Int]列表包含Foo输入的正确数量的数字,而是允许存在更多的Int ,并返回多余的。

Using this auxiliary function, you can handle the A case with two Foo s inside: you call the auxiliary function on the first Foo , and obtain the excess Int s, then you use those for the second Foo , and return the new excess Int s.使用这个辅助函数,您可以处理内部有两个FooA情况:您在第一个Foo上调用辅助函数,并获得多余的Int ,然后将它们用于第二个Foo ,并返回新的多余Int s .

(A more advanced approach would be to use a State [Int] monad, but the above basic approach should be fine.) (更高级的方法是使用State [Int] monad,但上述基本方法应该没问题。)

As @chi wrote above, creating a helper function something like : 如@chi上面所述,创建一个类似于以下内容的辅助函数:

helper :: [Int] -> Foo -> (Foo, [Int])

that returns the "extra" ints will get you pretty far, and also avoid having to count elements. 返回“额外”整数的代码将使您走得更远,并且还避免了必须对元素进行计数。

I'm assuming that your main problem with the A case is in handing the extra integers from one Foo to there other? 我假设您与A案有关的主要问题是将多余的整数从一个Foo传递到另一个?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM