Сокращение выражений на Haskell
Привет, я новичок в Haskell и в основном читаю от LYAH и Hutton. Недавно я наткнулся на этот фрагмент, где экземпляр Functor монады State, выраженный как:
instance Functor (State st) where
fmap f m = State $ \st -> let (a, s) = runState m st in (f a, s)
Это может быть уменьшено до:
instance Functor (State st) where
fmap f m = State $ (\(a,s) -> (f a,s)) . runState m
Кто-нибудь может объяснить рабочий процесс за этим сокращением?
Также, каковы некоторые хорошие ресурсы / советы о том, как изучить такие методы сокращения?
1 ответ
Если какие-либо из понятий, которые я привел (например, лямбда-функции), неясны, прочитайте о них в LYAH и поэкспериментируйте с ними в ghci
, Тогда вернитесь к этому ответу снова, и все должно немного проясниться!
Одна вещь, которая может сбивать с толку, если вы работаете с другими языками программирования, это то, что в Haskell вы можете использовать такую функцию, как
runState
и добавить один аргумент
runState m
и это все еще будет действительной функцией. Если вы добавите второй аргумент, вот так:
runState m st
это, наконец, вычислит значение. Это означает, что если runState
является функцией двух аргументов, то runState m
является функцией одного аргумента и может рассматриваться как любая другая функция одного аргумента.
Важный бит в вашем примере
\st -> let (a, s) = runState m st in (f a, s)
которые можно превратить в
(\(a,s) -> (f a,s)) . runState m
используя оператор для композиции функций, (.)
,
Первым шагом к пониманию того, как это возможно, является признание того, что let…in
Выражение можно переписать в лямбда-форме. Это означает, что
let y = f x in expr
можно записать как
(\y -> expr) (f x)
Обе эти строки будут связывать имя y
к стоимости f x
что на самом деле все, что нам нужно от let…in
выражение.
Если вы примените эти знания к
\st -> let (a, s) = runState m st in (f a, s)
вы увидите, что это можно переписать как
\st -> (\(a, s) -> (f a, s)) (runState m st)
и мы на полпути!
Определение состава функции таково:
f . g = \x -> f (g x)
Это означает, что в любое время у вас есть что-то похожее \x -> f (g x)
Вы можете заменить его просто f . g
,
Ну, в этом случае у нас есть нечто, похожее на это! Если мы говорим, что
f = \(a, s) -> (f a, s)
g = runState m
x = st
Мы видим, что
\st -> (\(a, s) -> (f a, s)) (runState m st)
\x -> f (g x)
это не более чем композиция функций, ожидающая выполнения. Таким образом, мы можем превратить его в
f . g
что, с нашими определениями f
а также g
,
f . g
(\(a, s) -> (f a, s)) . (runState m)
и вы можете оставить круглые скобки runState m
,