Когда вы пишете несколько более сложные функции, я замечаю, что $
используется много, но я не знаю, что он делает?
Что означает $mean/do в Haskell?
Ответ 1
$
является инфиксным "приложением". Он определяется как
($) :: (a -> b) -> (a -> b)
f $ x = f x
-- or
($) f x = f x
-- or
($) = id
Полезно избегать дополнительных круглых скобок: f (g x) == f $ g x
.
Особенно полезным местом для него является "заднее лямбда-тело", например
forM_ [1..10] $ \i -> do
l <- readLine
replicateM_ i $ print l
по сравнению с
forM_ [1..10] (\i -> do
l <- readLine
replicateM_ i (print l)
)
Или, как ни странно, он иногда появляется в секциях, когда выражается "применить этот аргумент к любой функции"
applyArg :: a -> (a -> b) -> b
applyArg x = ($ x)
>>> map ($ 10) [(+1), (+2), (+3)]
[11, 12, 13]
Ответ 2
Мне нравится думать о знаке $в качестве замены скобок.
Например, следующее выражение:
take 1 $ filter even [1..10]
-- = [2]
Что произойдет, если мы не поместим $? Тогда получилось бы
take 1 filter even [1..10]
и компилятор теперь будет жаловаться, потому что он думал бы, что мы пытаемся применить 4 аргумента к функции take
с аргументами 1 :: Int
, filter :: (a -> Bool) -> [a] -> [a]
, even :: Integral a => a -> Bool
, [1..10] :: [Int]
.
Это, очевидно, неверно. Так что же мы можем сделать вместо этого? Ну, мы могли бы поставить круглые скобки вокруг нашего выражения:
(take 1) (filter even [1..10])
Это не уменьшится до:
(take 1) ([2,4,6,8,10])
который затем становится:
take 1 [2,4,6,8,10]
Но мы не всегда хотим писать скобки, тем более, что мы начинаем входить друг в друга. Альтернативой является размещение знака $
между тем, куда будет проходить пара скобок, которая в этом случае будет:
take 1 $ filter even [1..10]