isAlphaNum :: Char -> Bool
isAlphaNum = (||) <$> isAlpha <*> isNum
我可以看到它有效,但我不明白Applicative(或Functor)的实例来自哪里。
通过这样的努力来使功能无点吗?
答案 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
,它将它的参数输入到f
和x
就是这样,
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
函数。