Подтвердить что ты не робот

Что означает $mean/do в Haskell?

Когда вы пишете несколько более сложные функции, я замечаю, что $ используется много, но я не знаю, что он делает?

4b9b3361

Ответ 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]