haskell,数据二叉树的Functor

时间:2016-03-06 17:22:18

标签: haskell functional-programming

我正在尝试为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不接受它。重点在哪里?

2 个答案:

答案 0 :(得分:1)

  

更优雅的解决方案呢?

完全没问题。所有其他未使用任何辅助函数的解决方案看起来或多或少都相同。我唯一要改变的是将=和名称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很重要。它限制了fmapFunctor实例的使用。现在这不是你遇到的问题:

  

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

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

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; DR fmap的类型由class Functor中的声明提供,它已由f instance中的sklearn.RandomForestClassifier(n_jobs=3,n_estimators=100,class_weight='balanced',max_features=None,oob_score=True) 指定1}}定义。

答案 1 :(得分:0)

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

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他们这是一个简单的方法。