[Haskell-beginners] types, parentheses, application, composition
Christopher Howard
christopher.howard at frigidcode.com
Mon Nov 26 09:17:35 CET 2012
On 11/25/2012 04:43 AM, Daniel Fischer wrote:
> On Sonntag, 25. November 2012, 02:27:31, Christopher Howard wrote:
>
> More like parentheses in algebra, they serve to group together parts of a
> (type) expression that would be grouped differently by the precedence and/or
> associativity of operators, e.g. in
>
> foo :: (Int -> a) -> a
> foo f = f 42
>
> The function arrow associates to the right, so without them, the signature
> would become Int -> (a -> a) which is an entirely different type.
>
> Or
>
> bar :: Either a (b -> a) -> b -> a
>
> where it's precedence. Prefix type application binds strongest (like function
> application at the value level), so we can't omit the parentheses, otherwise
> we'd get
>
> (Either a b) -> a -> b -> a
>
>
> Let's be more verbose and call it
>
> (.) :: (intermediate -> final) -> (original -> intermediate)
> -> original -> final
>
>
> The section (. sqr) is equivalent to \f -> f . sqr, so sqr is the second
> argument of (.) and we must unify its type with the type of the second
> argument of (.), which is (original -> intermediate).
>
> So original = Double, intermediate = Double, and here (.) is used at the more
> restricted type
>
> (.) :: (Double -> final) -> (Double -> Double) -> Double -> final
>
> the second argument is supplied, hence its type is removed, leaving
>
> (. sqr) :: (Double -> final) -> Double -> final
>
>
> Yup, modulo renaming, we have exactly that.
>
>
> Now, (. sqr) is used as the first argument of (.). So we must unify its type
> with (intermediate -> final), the type of (.)'s first argument.
>
> Now, the function arrow is right-associative, so we can also write
>
> (. sqr) :: (Double -> c) -> (Double -> c)
>
> and that makes it clear that
>
> intermediate = (Double -> c)
> final = (Double -> c)
>
> So the outer (.) is used at type
>
> (.) :: ((Double -> c) -> (Double -> c)) -> (original -> (Double -> c)) ->
> original -> (Double -> c)
>
> The first argument is supplied, so
>
> ((. sqr) .) :: (original -> (Double -> c)) -> original -> (Double -> c)
>
>
> Yup, modulo renaming and parentheses that can be omitted because -> is right-
> associative, that is exactly the same.
>
> It's just easier to see what corresponds to what with the parentheses.
>
>
> The pretty-printer of type signatures in ghci omits unnecessary parentheses.
> Read it (a -> (Double -> c)).
>
> While for small types like here, unnecessary parentheses can increase the
> readability, for larger types, they usually decrease readability much more
> (ever looked at Lisp code?), because all is drowned in parentheses.
>
Beautiful explanation. The clouds are starting to clear. In particular,
previously I did not understand that 1) parentheses are in all types but
are omitted for readability when possible, and 2) when an argument is
supplied to a function it unifies the supplied parameter type with the
argument type. Knowing this makes a huge difference in looking at these
transformations.
--
frigidcode.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 551 bytes
Desc: OpenPGP digital signature
URL: <http://www.haskell.org/pipermail/beginners/attachments/20121125/60532d02/attachment.pgp>
More information about the Beginners
mailing list