我试图了解仿函数是什么,我找到了这个教程/示例:
http://en.wikibooks.org/wiki/Haskell/Solutions/Applicative_Functors
data Tree a = Node a [Tree a]
上述类型的仿函数是:
instance Functor Tree where
fmap f (Node a ts) = Node (f a) (map (fmap f) ts)
有人可以帮助解释他们究竟做了什么以及他们为什么这样做了?我的理解是,仿函数允许您迭代数据类型。我似乎无法理解使用的语法?
答案 0 :(得分:3)
我以前从未见过Haskell,但我猜它是在定义一个数据类型(称为Tree),它由一个包含值的Node和一个Tree数组(它们将成为分支)组成原始树)。然后定义一个对函数和树进行操作的函数,并通过将函数应用于Node的值来创建一个新树,并将自身递归地应用于数组中的所有分支(使用map函数作为快捷方式)。 / p>
答案 1 :(得分:3)
基本上,在Haskell中,您可以将仿函数视为:
此外,仿函数还有一个操作 - fmap
- 了解其特定结构。
使用fmap
,您可以轻松地将结构保留转换应用于仿函数。例如,fmap (+ 1)
是一个向任何仿函数添加1的函数:
Prelude> fmap (+ 1) [1,2 ] -- using a list functor
[2,3]
Prelude> fmap (+ 1) (Just 2) -- using a maybe functor
Just 3
在您给出的示例中,Tree
被赋予一个Functor实例 - fmap
的实现 - 它可以理解树的结构,并为您提取摘要。
Functors,Applicative Functors,Monads,Monoids的绝佳资源是Learn You A Haskell。
答案 2 :(得分:3)
Functor
对于两个数据表示之间的映射非常有用。有时候这可能类似迭代,有时候不是。拥有这个通用的Functor
类型类允许我们忽略数据类型的实际结构(Maybe
,List
,Tree
),并只关注它们包含的数据。该数据类型的作者应该知道如何遍历/迭代该数据结构,以便他应该为此提供实现(以该数据类型的Functor
实例的形式)。我们必须提供的是f
函数,它使用a
并将其映射到b
。例如:
import Data.Char (toLower)
data Tree a = Node a [Tree a]
deriving Show
instance Functor Tree where
fmap f (Node a ts) = Node (f a) (map (fmap f) ts)
main :: IO ()
main = do print (toLower `fmap` (Node 'F' [])) -- Node 'f' []
print (toLower `fmap` (Just 'F')) -- Just 'f'
print (toLower `fmap` "FOO") -- "foo"
我们能够使用与toLower
相同的代码fmap
来小写这些字符。
因此,在定义Functor
实例时应该做的是使用模式匹配提取内部数据,并将接收到的回调函数f
应用于每个结果。
可以在fmap
模块中找到Control.Applicative
的中缀同义词,称为<$>
。
main :: IO ()
main = do print (toLower <$> (Node 'F' [])) -- Node 'f' []
print (toLower <$> (Just 'F')) -- Just 'f'
print (toLower <$> "FOO") -- "foo"