【问题标题】:haskell, Functor for Data Binary Treehaskell,数据二叉树的函子
【发布时间】:2016-03-07 16:40:42
【问题描述】:

我正在尝试为 Tree 编写函子(这种类型的形式如下所示)

data Tree a = Empty | Node a (Tree a) (Tree a) 

instance Functor Tree where
    fmap f Empty = Empty
    fmap f (Node a x y) =  Node (f a) (fmap f x) (fmap f y)

它似乎正在工作,但是更优雅的(我是 Haskell 的新手)解决方案呢? 第二期是讲师签名:fmap :: (a -> b) -> f a -> f b 对我来说,它是(a->b) -> Tree a -> Tree b,但编译器 ghci 不接受它。重点在哪里?

【问题讨论】:

  • 如果您在 GHC 中启用 DeriveFunctor 扩展,您可以让编译器为您派生 Functor 实例,方法是您将定义更改为 data Tree a = Empty | Node a (Tree a) (Tree a) deriving (Functor)。不过,您的实现是相当标准的,所以我怀疑您是否可以自己制作一个更“优雅”的实现。
  • 签名呢?
  • 我不明白你的签名问题,fmap 的类型是 (a -> b) -> f a -> fb,这就是你所拥有的,fTree
  • 你的回答对我来说没问题。为什么写成 f 而不是 Tree ?
  • @HaskellFun:不要忘记李的签名fmap 是不完整的,它缺少Functor f => 约束。

标签: haskell functional-programming


【解决方案1】:

更优雅的 [...] 解决方案怎么样?

完全没问题。所有其他不使用任何辅助函数的解决方案看起来或多或少相同。我唯一要改变的是=s 和名称xy 的对齐方式为lr(指左右分支):

instance Functor Tree where
  fmap _ Empty        = Empty
  fmap f (Node a l r) = Node (f a) (fmap f l) (fmap f r)

不过,这是我个人的看法。让我们进入真正的问题,fmap 的类型:

第二期是讲师写了签名:fmap :: (a -> b) -> f a -> f b[…]

首先,讲师的签名有些错误。 fmap的完整签名是

fmap :: Functor f => (a -> b) -> f a -> f b

约束Functor f 很重要。它将fmap 的使用限制为Functor 的实例。现在这不是您遇到的问题:

对我来说,它是(a->b) -> Tree a -> Tree b,但编译器 ghci 不接受它。重点在哪里?

啊,您尝试在 Functor Tree 实例中为 fmap 指定类型签名,对吧?

instance Functor Tree where
  fmap :: (a -> b) -> Tree a -> Tree b
  fmap = ...

嗯,这是不允许的。毕竟fmap的类型不是(a -> b) -> Tree a -> Tree b,而是上面更通用的那个。这有点——但不完全——类似于为单个绑定使用两个类型签名:

foo :: Eq a => a ->  a -> Bool
foo ::        () -> () -> Bool

这也是不允许的。请注意,如果您真的愿意,可以启用实例签名with an extension。如果你只是为了文档,可以使用注释代替-XInstanceSigs

instance Functor Tree where
  -- fmap :: (a -> b) -> Tree a -> Tree b
  fmap = ...

TL;DRfmap 的类型由它在class Functor 中的声明给出,它已经由您在instance 定义中选择的f 指定。

【讨论】:

    【解决方案2】:

    您的解决方案非常优雅。另一种选择是使用traverse 定义fmap

    import Data.Traversable
    
    -- Preorder traversal based on the way you defined the Node constructor. Could use any traversal.
    instance Traversable Tree where
      traverse _ Empty = pure Empty
      traverse f (Node v l r) = Node <$> f v <*> traverse f l <*> traverse f r 
    
    instance Functor Tree where
      fmap = fmapDefault
    
    instance Foldable Tree where
      foldMap = foldMapDefault
    

    我不会说这更优雅,但如果你想要所有这些实例,并且不想derive 它们,这是一种简洁的方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-06-04
      • 2020-02-07
      • 2019-04-08
      • 1970-01-01
      • 2018-06-29
      • 1970-01-01
      • 2021-11-20
      相关资源
      最近更新 更多