Haskell 有人能解释一下应用程序实例在代码中的位置吗? isAlphaNum::Char->Bool isAlphaNum=(| |)isAlpha isNum

Haskell 有人能解释一下应用程序实例在代码中的位置吗? isAlphaNum::Char->Bool isAlphaNum=(| |)isAlpha isNum,haskell,functor,applicative,Haskell,Functor,Applicative,我可以看出它是有效的,但我不明白Applicative(或Functor)的实例来自哪里。这是((->)r)的Applicative实例,函数来自一个普通类型。它通过复制单个参数以用于所有函数,将具有相同第一个参数类型的函数合并为单个函数()是函数组合,pure是常量,下面是()的意思: isAlphaNum :: Char -> Bool isAlphaNum = (||) <$> isAlpha <*> isNum 这个函数最好称为 ((->)r)函子也是读

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

这是
((->)r
)的
Applicative
实例,函数来自一个普通类型。它通过复制单个参数以用于所有函数,将具有相同第一个参数类型的函数合并为单个函数
()
是函数组合,pure是常量,下面是
()
的意思:

isAlphaNum :: Char -> Bool
isAlphaNum = (||) <$> isAlpha <*> isNum 
这个函数最好称为

((->)r)
函子也是
读取器
单子,其中共享参数是“环境”值,例如:

s :: (r -> a -> b) -> (r -> a) -> r -> b
s f g x = f x (g x)

我不会说为了使函数无点而这样做是很常见的,但在某些情况下,一旦你习惯了这个习惯用法,它实际上可以提高清晰度。例如,您给出的示例,我可以很容易地理解为“是一个字符,一个字母或数字”。

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

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

newtype Reader r a = Reader (r -> a)

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

应该注意的是,使用提升函数可以获得类似的效果,例如:

isAlphaNum c = (isAlpha c) || (isNum c)
或者,使用((->)r的monad实例而不是应用程序实例:

import Data.Char
import Control.Applicative 

isAlphaNum = liftA2 (||) isAlpha isNumber
[题外话]

既然您知道了如何将一个参数分配给两个中间函数,并将结果分配给一个二进制函数,那么有一种情况与此相关,即您希望将两个参数分配给一个中间函数,并将结果分配给一个二进制函数:

import Data.Char
import Control.Monad 

isAlphaNum = liftM2 (||) isAlpha isNumber

此模式通常用于
比较
功能

还有
Control.Concatenative
,它将一些标准的连接组合词引入Haskell。您的示例可以是
bi-isAlpha-isNumber(| |)
fst`biAp`(| |)
。这里不一定要显示,但是控制。串联式确实有助于提高许多无点表达式的易读性,因为这就是串联式编程的全部内容。
isAlphaNum
=
(\c->(((| |)isAlpha)c(isNum c))
=
(\c->isAlpha c | | isNum c)
(…只是旁注)。
import Data.Char
import Control.Monad 

isAlphaNum = liftM2 (||) isAlpha isNumber
import Data.Function

orFst = (||) `on` fst

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