Каково использование знака "$" при манипулировании строками в Haskell?
Этот код проверяет, является ли данный пароль действительным в соответствии с ограничениями в требованиях
import Data.Char
strong :: String -> Bool
strong password = all ($ password) requirements
where requirements = [minLength 15, any isUpper, any isLower, any isDigit]
minLength n str = n <= length str
Ответы
Ответ 1
all ($ password) requirements
where requirements = [minLength 15, any isUpper, any isLower, any isDigit]
По определению all
приведенное выше эквивалентно
($ password) (minLength 15) &&
($ password) (any isUpper) &&
($ password) (any isLower) &&
($ password) (any isDigit)
Теперь, в Haskell, так называемая секция (+-*/ x)
обозначает (\y -> y +-*/ x)
, что бы ни был оператор +-*/
(который $
, в вашем случае). Итак, получим
(minLength 15 $ password) &&
(any isUpper $ password) &&
(any isLower $ password) &&
(any isDigit $ password)
Наконец, оператор $
определяется следующим образом: f $ x = f x
, т.е. это оператор приложения функции. Мы также упростим код выше:
minLength 15 password &&
any isUpper password &&
any isLower password &&
any isDigit password
Ответ 2
$
означает "Назначение функций".
> :t ($)
($) :: (a -> b) -> a -> b
$
может использоваться для предоставления параметра функции. В этом случае вы используете его для применения "пароля" к каждой функции, "требования" имеют и имеют тип:
-- because $ is infix, left and right param are the 1st and 2nd respectively
-- partial apply with the right param will still need the left one (a->b)
:t ( $ "a")
( $ "a") :: ([Char] -> b) -> b --where "b" is a bool in this case
кажется знакомым?
:t (\f -> f "a")
(\f -> f "a") :: ([Char] -> b) -> b
$ password
и (\f -> f password)
имеют один и тот же тип и то же поведение: возьмите функцию и примените ее над a
.
Когда вам нужно применить функцию над списком, вы просто поместите эту функцию в одиночку.
Но в этом случае вам нужно применить функции из списка к "password". Если вы опустите $
, он попытается сделать "пароль (любой isLower)", например, который не имеет никакого смысла.
Но вы можете сделать это, используя lambda как all (\f -> f password) ...
, чтобы применить каждую функцию к password
, или вы можете сделать это с помощью $
.