isAlphaNum :: Char -> Bool
isAlphaNum = (||) <$> isAlpha <*> isNum
Я вижу, что это работает, но не понимаю, откуда берутся экземпляры Applicative
(или Functor
).
Вы получаете экземпляры так называемых статических стрелок (см. «Применимое программирование с эффектами» Конора МакБрайда и др.) Бесплатно из пакета Control.Applicative
. Итак, любой тип источника, в вашем случае Char
, порождает аппликативный экземпляр, где любой другой тип 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 имел лучшую синтаксическую поддержку для аппликативов (возможно, что-то вроде двухуровневых языков).