На днях я читал комментарии к Monad Challenge (которую я очень рекомендую любому новичку в Haskell, как и я), и Я закончил на этот поток, где я читал, что ($) = id
.
Я не знаю о пугающих людях, но многие языки программирования имеют концепции, которые лучше всего демонстрируются небольшими примерами, которые заставляют людей говорить "whoa".
Например, удивительно, что append() в Prolog можно запустить "назад" из конкатенированного результата, чтобы получить все списки, которые могут быть объединены для его создания. Или что оператор монадического связывания в Haskell ( → =) может быть определен в терминах join и fmap, или что ($) = id.
($) = id !?
< пробует это в Raskell/Ghci >
Теперь я вижу, почему это правда, но все же... Whoah!! Спасибо за это! (...)
Затем я проверил код base
-4.10.0.0, ища определения ($)
и id
, но правильно наверху я читал это:
NOTA BENE: Do NOT use ($) anywhere in this module! The type of ($) is slightly magical (it can return unlifted types), and it is wired in. But, it is also *defined* in this module, with a non-magical type. GHC gets terribly confused (and *hangs*) if you try to use ($) in this module, because it has different types in different scenarios. This is not a problem in general, because the type ($), being wired in, is not written out to the interface file, so importing files don't get confused. The problem is only if ($) is used here. So don't!
И их реализации:
-- | Identity function.
id :: a -> a
id x = x
-- | Application operator.
{-# INLINE ($) #-}
($) :: (a -> b) -> a -> b
f $ x = f x
Я попытался поменять местами один на другой на GHCi, и все, что у меня было, было ошибкой типа (как я и ожидал). Теперь у меня больше вопросов, чем с того, с чего я начал:
- Что они означают, говоря, что
($) = id
? - В каких случаях это утверждение истинно? Означает ли это, что я могу использовать один вместо другого?
- В
base
подразумевается, что($)
является "слегка магическим (он может возвращать неперекрытые типы)" и "подключен к сети"? - А как насчет "разных типов в разных сценариях"? Я думал, что, поскольку Haskell является строго типизированным языком, как только вы определяете подпись типа, эта подпись сохраняется до конца Времени. Разве это не так? Существуют ли случаи, когда можно изменить тип функции?