有人可以解释在此代码中出现Applicative实例的位置吗?

时间:2012-01-26 02:31:32

标签: haskell

isAlphaNum :: Char -> Bool
isAlphaNum = (||) <$> isAlpha <*> isNum 

我可以看到它有效,但我不明白Applicative(或Functor)的实例来自哪里。

通过这样的努力来使功能无点吗?

3 个答案:

答案 0 :(得分:18)

这是Applicative的{​​{1}}实例,来自常见类型。它通过复制一个用于所有这些参数的参数,将具有相同第一个参数类型的函数组合到一个函数中。 ((->) r)是函数组合,纯(<$>),这是const转换为:

(<*>)

这个功能可能更好地称为the S combinator

s :: (r -> a -> b) -> (r -> a) -> r -> b s f g x = f x (g x) 仿函数也是((->) r) monad,其中共享参数是“环境”值,例如:

Reader

我不会说它是常用这样做是为了使函数无点,但在某些情况下,一旦你习惯了成语,它实际上可以提高清晰度。例如,你给出的例子,我可以非常容易地阅读,意思是“字母是一个字母或数字”。

答案 1 :(得分:7)

您可以从Control.Applicative包中免费获得所谓静态箭头的实例(请参阅Conor McBride等人的“使用效果进行应用编程”)。因此,在您的情况Char中,任何源类型都会产生一个Applicative实例,其中任何其他类型a都会映射到Char -> a类型。

当你将这些中的任何一个组合起来时,比如将一个函数f :: Char -> a -> b应用于值x :: Char -> a,语义就是你创建一个新函数Char -> b,它将它的参数输入到fx就是这样,

f <*> x = \c -> (f c) (x c)

因此,正如您所指出的,这使您的示例等同于

isAlphaNum c = (isAlpha c) || (isNum c)

在我看来,这样的努力并不总是必要的,如果Haskell对应用程序有更好的语法支持(可能类似于2级语言),它看起来会更好。

答案 2 :(得分:3)

应该注意的是,通过使用提升功能可以获得类似的效果,例如:

import Data.Char
import Control.Applicative 

isAlphaNum = liftA2 (||) isAlpha isNumber

或者,使用(( - &gt;)r)的monad实例代替应用实例:

import Data.Char
import Control.Monad 

isAlphaNum = liftM2 (||) isAlpha isNumber

<强> [题外话]

现在您已经知道如何将一个参数分发给两个中间函数,并将结果分发给二元函数,现在有一些与您想要分发的相关案例< em>一个中间函数的em>两个参数和二元函数的结果:

import Data.Function

orFst = (||) `on` fst

-- orFst (True,3) (False, 7)
--> True

这种模式是例如通常用于compare函数。