I was wondering: Does writing this:
(<$>) :: (a -> b) -> Parser a -> Parser b
(<$>) f p1 s = case p1 s of
Just (r1 , s') -> Just (f r1, s')
Nothing -> Nothing
instead of this:
(<$>) :: (a -> b) -> Parser a -> Parser b
f <$> p1 = \s -> case p1 s of
Just (r1 , s') -> Just (f r1, s')
Nothing -> Nothing
change anything?
CodePudding user response:
No, it doesn't change anything, but.
You have actually changed two things at once. The first is switching from prefix to infix when defining the function; the other is switching from putting all arguments to the left to having one on the right in a lambda.
Switching from prefix to infix never changes anything. So if you had done this:
(<$>) f p1 s = ...
VS.
(f <$> p1) s = ...
there would be no but in my answer.
In this case, switching from arguments on the left to arguments on the right changes nothing. However, there are two things that can cause that change to actually do something. First, if there is no type signature, and one of the arguments on the RHS has a typeclass-polymorphic type, that type will become either an error or a monomorphic type. This is the monomorphism restriction; see What is the monomorphism restriction? for more details.
Second, for GHC-compiled programs, if there is a let
or where
block on the RHS that do not mention the variable that was moved to the RHS, then the values in the block may be calculated and stored rather than recalculated on each call of the function. For example, the following two definitions are completely equivalent:
f :: Int -> Int
f x = let y = 3 5 in y
VS.
f = \x -> let y = 3 5 in y
But these pairs are not equivalent to each other:
f :: Int -> Int
f x = let y = 3 5 in y
VS.
f = let y = 3 5 in \x -> y
f :: Int -> Int
f x = y where y = 3 5
VS.
f = \x -> y where y = 3 5
In both cases, the value 8
is recomputed on each call for the first in the pair, but computed once on the first call and stored reused on later calls for the second in the pair.