HW:以特定方式展开列表

时间:2013-03-21 00:02:18

标签: haskell functional-programming unfold

在Haskell的编程中,Graham Hutton定义了列表展开如下:

unfold :: (b -> Bool ) -> (b -> a) -> (b -> b) -> b -> [a]
unfold p h t x | p x = []
| otherwise = h x : unfold p h t (t x)

定义一个函数

• listUnfold :: (b -> Bool) -> (b -> a) -> (b -> b) -> b -> [a]

与上面的类似,但在其实现中使用unfoldr并且是非递归的。

我已经尝试了一段时间来解决上面的问题,但我仍然可以设法这样做(在Haskell和一般的函数式编程中相当新)。

我的尝试:

listUnfold :: (b -> Bool) -> (b -> a) -> (b -> b) -> b -> [a]
listUnfold f h t x 
    | f x == True   = []
    | otherwise     = h x : 
        listUnfoldr (\x -> if f x then Nothing else Just ((h x), (t x))) x

在英语中,如果f x为真,则返回空列表。否则,使用h x作为头部并将展开的结果作为尾部附加。 Unfoldr获取列表(x:xs)应该以{{1​​}}为头,x为尾部进行递归。

p / s:我可能非常错误地做这件事。

2 个答案:

答案 0 :(得分:6)

你差不多了!原始函数使用函数p(对于'谓词')来确定我们是否已完成展开,h以应用于每个元素,以及t(对于'转换')将一个元素转换为列表其余部分的种子。

unfoldr需要单个函数f :: b -> Maybe (a,b),如果我们已完成展开则返回Nothing,或Just (x, y),其中x是要添加的元素到列表中,y是列表其余部分的种子。

因此f中的unfoldr负责pht的所有三个功能。 Nothing - 或 - Just二分法扮演布尔函数p的一部分,元组的第二个元素执行t为种子提供种子的工作列表的其余部分。

这是我的解决方案(为了清楚起见,我已将您问题中的变量重命名):

listUnfold pred f trans seed =
    unfoldr (\x -> if pred x
                   then Nothing
                   else Just (f x, trans x)) seed

当然,当一个值出现在定义的右端时,正如seed在这里所做的那样,你可以利用Haskell的性感语法进行调整并完全抛弃:

listUnfold pred f trans = unfoldr (\x -> if pred x
                                         then Nothing
                                         else Just (f x, trans x))

形式上,这种转变称为eta reduction

答案 1 :(得分:2)

这是definition of unfoldr

unfoldr                 :: (b -> Maybe (a, b)) -> b -> [a]
unfoldr f b  =
  case f b of
   Just (a,new_b) -> a : unfoldr f new_b
   Nothing        -> []

这是Hutton的unfold,稍微改写一下,使用case代替守卫:

unfold :: (b -> Bool ) -> (b -> a) -> (b -> b) -> b -> [a]
unfold p h t x =
  case p x of
    True  -> []
    False -> h x : unfold p h t (t x)

一些观察结果:

  • 通过比较类型,我们可以看到unfoldrunfold共享相同的最终参数类型和相同的结果类型。
      {li> bunfoldr的定义中xunfold的定义基本上是同一个变量。
    • 希望我们也可以匹配两个函数的定义,以便结果相同。
  • 每个函数都包含一个case表达式,带有两个分支。
  • 在每个函数中,其中一个分支导致[]
    • 因此,当p x = True时,我们需要f x = Nothing
  • 在每个函数中,另一个分支导致{-something-} : {-recursive-call-}
    • 因此,当p x = False时,我们需要f x = Just ({-something-}, {-something-else-})

到目前为止,unfold p h t x = unfoldr f x where f = ...应该很清楚,并且进行推理链并填写f的定义并不太难。