I recently saw a simple example that brought <*
and *>
to light.
validate :: String -> Maybe String
validate s = if s=="" then Nothing else Just s
>validate "a" *> validate "b"
Just "b"
>validate "" *> validate "b"
Nothing
>validate "a" <* validate "b"
Just "a"
>validate "a" <* validate ""
Nothing
>validate "a" <* validate "b" <* validate "c"
Just "a"
>validate "a" *> validate "b" <* validate "c"
Just "b"
This shows that the effects are important even if the values they produce are not.
My question is about the type signatures.
(*>) :: f a -> f b -> f b
(<*) :: f a -> f b -> f a
I can see how one could reason "Obviously we have an Applicative - so that says something about behavior in general. For operator *>
, since we are throwing away the left value, the only possible meaning this function could have would be how the effect of the left hand side affects the entire operation."
In the case of Maybe
- then it seems that yes - the behavior is implied. For Either
, likewise the implication holds and the error would be propagated on an effect 'failure'.
Note I can only say the above because I now know how the implementation works, where my question pertains to the seasoned functional programmer who sees a signature like this the first time.
I have read where a type signature like [a] -> b :: Int
(probably not real code there) all but implies the implementation as the length of the list.
I have also searched for "implying implementation from type signature" and found that people have-been/are working on such things - but in general cannot be done (Uh - without that new GitHub thing :--)
So perhaps I have answered my own question but would appreciate any other answers or comments. I am still new to Haskell and after a number of false starts over the years, it is finally starting to sink in. And I have only scratched the surface...
Thanks
Basic Logic - The Implication Operator In binary logic, we know about operators such as AND, OR, NOT. Another operator that is important in logic and in test design is the impliesoperator. A ->B (A impliesB)
In binary logic, we know about operators such as AND, OR, NOT. Another operator that is important in logic and in test design is the impliesoperator. A ->B (A impliesB) Another way of stating the implies operator is with if…then: IF A THEN B The truth table is: A
Another way of stating the implies operator is with if…then: IF A THEN B The truth table is: A B A ->B 0 0 1 0 1 1 1 0 0 Logical contradiction!
The implication construct can be used only with property definitions. It cannot be used in sequences. There are 2 types of implication: The overlapped implication is denoted by the symbol |->. If there is a match on the antecedent, then the consequent expression is evaluated in the same clock cycle.
(*>) :: f a -> f b -> f b (<*) :: f a -> f b -> f a
Do these type signatures actually imply the behavior shown above?
Of course not. The two operations could be implemented simply as
apR :: (Applicative f) => f a -> f b -> f b
apR a b = b
apL :: (Applicative f) => f a -> f b -> f a
apL a b = a
just ignoring the Applicative
constraint on f
.
And in the same way [a] -> Int
does not imply the implementation being length
. It could just as well be
foo :: [a] -> Int
foo _ = 42
But in both cases these are not the "right" implementations in the sense that the inferred types are different from the signatures given.
Your question is then, perhaps, a bit different, like, suppose there is an implementation with the matching inferred type. Does it follow that it does the thing we intended?
The answer seems to still be no. For one, we can define
apR2 :: (Applicative f) => f a -> f b -> f b
apR2 a b = pure (\a _ b -> b) <*> a <*> b <*> b
For some types, like your examples, it won't make a difference. But in general, doing the effects twice is different than doing them only once.
Another, even more meaningfully "wrong" implementation (with thanks to Daniel Wagner for the comments), is
apR2b :: (Applicative f) => f a -> f b -> f b
apR2b a b = pure (\b a -> b) <*> b <*> a
Now even your examples won't always work, because the order of effects is different -- it "does" b
's first, before the a
's.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With