我一直在研究Scala(和Haskell的扩展)已有一段时间了,我完全被他们的类型系统和功能范例所捕获。最近我偶然发现了“类型级别编程”,并被拖入了Functors和其他我没有听说过的东西(除了Monad,我知道这是一种神秘的东西,但不知道该使用什么它!)。 我研究了Haskell中的概念(并且顺便通过它的类型系统和类型推理能力而被迷惑了),我有一种对纯粹技术层面的Functor,PointedFunctor,ApplicativeFunctor或Monoid类型意味着什么的坚定把握。 (我仍然不知道Monad在技术水平上是什么样的)但是我觉得自己像个白痴,因为我看不到所有这些用处,除非可能获得了一些概念的良好分类(?)。这些东西有用吗?为什么生活如此复杂?为什么要研究这些东西并将它们分类为不同的类?
答案 0 :(得分:9)
为什么要让生活如此复杂?
他们都在那里让生活变得更简单!
首先,它们使我们编写的代码更清晰,更清晰。
其次,它们增加了我们的表现力而没有添加真正的新语言特征。 例如,Monads允许您使用标准语法来表达复杂的计算上下文,Functors允许您以标准方式思考和编程数据结构,而Applicative Functors可以让您像对待简单数据一样简单地处理有效或复杂的计算上下文,让您在纯数据之外干净地使用功能范例。
它们都有助于代码重用,并帮助我们理解彼此的代码,因为它们为我们提供了一种标准的思考方式。
一旦你习惯了它们,你就不想没有它们了!
答案 1 :(得分:5)
他们都是抽象。例如。 monoid是支持零元素和加法的东西(必须是关联的)。例子是整数,列表,字符串等。我认为对于所有这些不同的类型都有一个共同的“接口”是相当不错的。
那为什么它们有用呢?例如,您可以为所有幺半群编写通用求和函数。不是为字符串,整数等编写一个,而是只编写一个通用函数。我认为这非常有用。
答案 2 :(得分:4)
我们首先要问:什么是仿函数,monad,...... 。除非我们知道这些概念是什么(意思是),否则很难谈论它们的用途。
这些概念来自category theory。 它们源于这样一个事实,即数学中的许多对象(以及因此在函数式编程中)共享一些共同的抽象属性。一旦我们了解并理解了这些属性,我们就可以使用它们编写非常通用的代码,这些代码可以重复用于大量任务。
举个例子:每个人都知道功能
map :: (a -> b) -> ([a] -> [b])
拥有从a
到b
的功能,我们可以创建一个适用于列表[a]
的函数。 Functors是这个概念的概括。任何可以这种方式映射(并保留functor laws)的东西都称为仿函数。所以Functor
判决
fmap :: Functor f => (a -> b) -> (f a -> f b)
如果列表f
变为[]
。使用fmap
,我们可以映射列表(它等于map
),也可以映射到Maybe
,各种集合,树,甚至函数。
另见
答案 3 :(得分:3)
此外,我想指出单子不是“神秘的”。特别是类似容器的monad(list,Maybe,Identity)很容易理解。它们与仿函数类似,但有一个转折点:使用fmap
保留原始仿函数的“形状”(例如列表中元素的数量),例如:您无法使用fmap
来实现filter
之类的内容。这就是为什么monads有一个名为“bind”的函数(在Haskell中它是(>>=)
)允许这种事情,但它们也不是魔法(例如对于列表,它与好的concatMap
相同)。另外monad具有函数return
来包装单个值。
现在很多其他的,而不是“像容器一样”的东西都是monad。有些monad可以对“存储的计算”进行操作(Cont
用于continuation monad)。他们可以提供(Reader
),收集(Writer
)或持有(State
)某种“附加背景”。一个非常有用的“背景”是“世界其他地方的状态”,更为人所知的是IO
。在这种情况下,类型系统(尤其是多态和类型类所施加的限制)可以屏蔽不需要的交互,并强制执行某种计算顺序(这在懒惰的语言中并不是微不足道的),因此我们不需要肮脏的黑客或语言 - 门是为了用纯语言做IO。有些人认为这有点神奇,但它只是巧妙地使用了类型系统,monad并不是解决这个问题的唯一方法(例如,Clean语言使用“唯一性类型”)。
答案 4 :(得分:1)
“这些有用的东西是什么?” 啊!您可以使用它们来编写FizzBuzz: http://dave.fayr.am/posts/2012-10-4-finding-fizzbuzz.html