문제

Hi I am a Haskell newbie and mostly reading from LYAH and Hutton. Recently I came across this snippet where the Functor instance of a State monad, expressed as:

instance Functor (State st) where
    fmap f m = State $ \st -> let (a, s) = runState m st in (f a, s)

This can be reduced to:

instance Functor (State st) where 
    fmap f m = State $ (\(a,s) -> (f a,s)) . runState m

Can anyone explain the workflow behind this reduction?

Also what are some good resources/advice on how to learn such reduction techniques?

도움이 되었습니까?

해결책

If any of the concepts I bring up (such as lambda functions) are unclear, read about them in LYAH and play around a little with them in ghci. Then come back to this reply again and everything should clear up a bit!

One thing that might be confusing if you are coming from other programming languages is that in Haskell, you can take a function such as

runState

and add one argument

runState m

and it will still be a valid function. If you then add a second argument, like so:

runState m st

it will finally compute a value. This means that if runState is a function of two arguments, then runState m is a function of one argument and can be treated like any other function of one argument.


The important bit in your example is

\st -> let (a, s) = runState m st in (f a, s)

which can be turned into

(\(a,s) -> (f a,s)) . runState m

using the operator for function composition, (.).


The first step to understanding how that is possible is recognising that a let…in expression can be rewritten in a lambda form. This means that

let y = f x in expr

can be written as

(\y -> expr) (f x)

Both of those lines will bind the name y to the value of f x, which is really all we need of a let…in expression.

If you apply that knowledge to

\st -> let (a, s) = runState m st in (f a, s)

you will see that it can be rewritten as

\st -> (\(a, s) -> (f a, s)) (runState m st)

and we're halfway there!


The definition of function composition is this:

f . g = \x -> f (g x)

This means that any time you have something that looks like \x -> f (g x) you can replace it with just f . g.

Well, in this case we do have something that looks like that! If we say that

f = \(a, s) -> (f a, s)
g = runState m
x = st

We see that

\st -> (\(a, s) -> (f a, s)) (runState m st)
\x  -> f                     (g          x)

is no more than function composition waiting to happen. So we can turn it into

f . g

which was, with our definitions of f and g,

f                     . g
(\(a, s) -> (f a, s)) . (runState m)

and you are allowed to drop the parentheses around runState m.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top