Сокращение выражений на 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,

Другие вопросы по тегам