Just (+) <*> Just 3 <*> Just 5
Just 8
pure (+) <*> Just 3 <*> Just 5
Just 8
pure (*3) <*> [0..10]
[0,3,6,9,12,15,18,21,24,27,30]
Just (*3) <*> [0..10]
Couldn't match type ‘[]’ with ‘Maybe’
Expected type: Maybe b
Actual type: [b]
In the second argument of ‘(<*>)’, namely ‘[0 .. 10]’
In the expression: Just (* 3) <*> [0 .. 10]
In an equation for ‘it’: it = Just (* 3) <*> [0 .. 10]
When are pure
and Just
interchangeable and when are they different?
Just tuning is often used by ensembles (such as for choral or orchestra works) as the players match pitch with each other "by ear." The "equal tempered scale" was developed for keyboard instruments, such as the piano, so that they could be played equally well (or badly) in any key.
What sounds "good" is a very subjective call. Some people describe harmonies in Just Intonation as being "full" or "rich", while others describe them as "bland" or "lifeless". However, most people would agree that JI harmonies are considerably smoother than tempered harmonies. There are several reasons for this.
An ideal system (for Western people) would be based on the natural harmonic series, because we love how harmonics sound. This kind of tuning system is called just intonation. It sounds lovely! Unfortunately, just intonation makes it impossible to change keys or tune your guitar.
Applying the first part of this concept, some scholars refer to Pythagorean tuning as "3-limit just intonation," since all intervals are derived either from fifths (3:2) or octaves (2:1), ratios involving 3 as the largest prime.
pure
is an overloaded operation. It is defined for all types that implement the Applicative
class. One of the types that do that is Maybe
. So pure
in that context is the same as Just
. But there are other types that also implement Applicative
such as []
(lists). In that case, pure
means singleton (i.e. the function that takes a single value and returns the one-element list that contains that value). So
pure (*3) <*> [0..10]
really means:
[(*3)] <*> [0..10]
and not
Just (*3) <*> [0..10]
In this last example you are trying to mix lists with maybes which is why GHC rejects it. In general, haskell figures out what is the exact meaning of pure
based on the context, e.g. if you try to use it with maybes, it will interpret it as Just
, if you use it with lists interpret it as singleton.
The pure
function returns a polymorphic value:
Prelude> :t pure "foo"
pure "foo" :: Applicative f => f [Char]
For Maybe
, pure
is just defined to be Just
:
instance Applicative Maybe where
pure = Just
-- ...
Other types provide different definitions; as an example, it is defined for lists as
instance Applicative [] where
pure x = [x]
-- ...
Specifying a type for the return value tells Haskell which Applicative
instance to use for the definition of pure
.
Prelude> pure "foo" :: [[Char]]
["foo"]
Prelude> pure "foo" :: Maybe [Char]
Just "foo"
In addition to providing an explicit type, Haskell can infer which type to use base on how the value is used. For instance, (<*> [1..5]) :: (Num a, Enum a) => [a -> b] -> [b]
, so in pure (+3) <*> [1..5]
, we know pure (+3)
has to have type [a -> b]
. Similarly, in pure (+3) <*> Just 5
, we know that pure (+3)
must have type Maybe (a->b)
.
In general, in any expression pure f <*> g
, the type of g
will determine what type of value pure f
needs to return.
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