【问题标题】:Haskell Map Function for Algebraic Data types代数数据类型的 Haskell 映射函数
【发布时间】:2018-08-02 18:03:00
【问题描述】:

我有一个如下定义的代数数据类型 Newb。现在我想在不使用递归的情况下为其编写一个自定义映射函数。此外,我还有一个 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))

以上是我实现这个功能的尝试。我不能比这更进一步,我不明白我在这里做错了什么。任何帮助将不胜感激。

【问题讨论】:

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


    【解决方案1】:

    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 bNode 也很容易做到这一点。

    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,有一个非常有用的功能,称为 typehole,您可以使用它来确定您需要哪种类型。所以(我在调试你的函数时正是这样做的)如果你写

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

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

    【讨论】:

      【解决方案2】:

      不使用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]
      

      【讨论】:

        猜你喜欢
        • 2020-05-16
        • 2017-05-22
        • 1970-01-01
        • 1970-01-01
        • 2023-01-29
        • 1970-01-01
        • 1970-01-01
        • 2017-11-22
        • 1970-01-01
        相关资源
        最近更新 更多