Каково использование знака "$" при манипулировании строками в 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, или вы можете сделать это с помощью $.