代数数据类型的Haskell映射函数

时间:2018-08-02 18:03:00

标签: haskell functional-programming higher-order-functions fold algebraic-data-types

我有一个如下定义的代数数据类型Newb。现在我想为其编写一个自定义的map函数而不使用递归。此外,我还有一个foldNewb函数也可以提供帮助。

 data Newb a = Leaf a | Node [Newb a]


foldNewb:: (a->b)->([b]->b)->Newb a -> b
foldNewb f _ (Leaf a) = f a
foldNewb f1 f2 (Node a) = f2 (map (foldNewb f1 f2) a)


Newbmap :: (a->b)-> Newb a -> Newb b

Newbmap f (Leaf a) = (Leaf (f a))
Newbmap f (Node a) = (Node (foldNewb f concat a))

上面是我实现该功能的尝试。我无能为力了,我不明白我在做什么错。任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:5)

tl; dr 这是您的功能。但是我建议继续阅读以了解我是如何提出的,以便您可以进行思考。

newbmap :: (a->b)-> Newb a -> Newb b
newbmap f = foldNewb (Leaf . f) Node

您已经很接近了,并且正确使用了foldNewb,但是您想得太多了。

首先,您无法命名函数Newbmap。大写名称保留用于类型。因此,我们将其称为newbmap。现在,foldNewb已经处理了LeafNode这两种情况,因此我们根本不必在newbmap中进行模式匹配。实际上,您的第一个newbmap情况确实可以完成foldNewb的工作,因此,让我们考虑第二个情况。

newbmap :: (a->b)-> Newb a -> Newb b
newbmap f (Node a) = (Node (foldNewb f concat a))

我们想折叠我们的数据结构。特别是,我们希望fold调用完全产生新的数据结构。最后,我们 无需明确使用Node,因为foldNewb已经对我们有用。

newbmap :: (a->b)-> Newb a -> Newb b
newbmap f a = foldNewb f concat a

现在,在第一种情况下,我们需要一个函数a -> Newb b(因为结果将是Newb b类型)。您已通过f :: a -> b,它非常接近您想要的。我们只需要用一个函数b -> Newb b来组成它,Leaf就可以做到这一点。

newbmap :: (a->b)-> Newb a -> Newb b
newbmap f a = foldNewb (Leaf . f) concat a

对于第二个参数,您需要[Newb b] -> Newb b,这很容易由Node完成。

newbmap :: (a->b)-> Newb a -> Newb b
newbmap f a = foldNewb (Leaf . f) Node a

而且(尽管没什么区别),我们可以指向最后一个参数。

newbmap :: (a->b)-> Newb a -> Newb b
newbmap f = foldNewb (Leaf . f) Node

因此有一个有效的newbmap函数。现在,关于我如何提出所有这些类型,如果您使用的是GHC,则有一个非常有用的功能,称为“ 类型孔”,您可以使用它来识别所需的类型。所以(如果您编写函数,我在调试功能时就做到了)

newbmap :: (a->b)-> Newb a -> Newb b
newbmap f = foldNewb _1 _2

然后,您会收到非常具体的GHC消息,告诉您_1 :: a -> Newb b_2 :: [Newb b] -> Newb b。然后,您面临的挑战就是简单地找到具有这些特定类型的函数。这是我提出Leaf . fNode的地方。

答案 1 :(得分:1)

不使用foldNewb

data Newb a = Leaf a | Node [ Newb a]
  deriving (Show)

newbMap :: (a -> b) -> Newb a -> Newb b
newbMap f (Leaf a) = Leaf (f a)
-- since a :: [Newb a] in the below clause, we can map (newbMap f) over the elements 
newbMap f (Node a) = Node (map (newbMap f) a)

tree = Node [ Leaf 1, Node [Leaf 2, Leaf 3], Leaf 4]
mapped = newbMap (+1) tree -- Node [Leaf 2,Node [Leaf 3,Leaf 4],Leaf 5]