[Haskell-beginners] map type explanation

Josh Friedlander joshuatfriedlander at gmail.com
Sat Dec 19 18:31:49 UTC 2020


I'm a real beginner, but IIUC might the misunderstanding here be that OP
was assuming that since all *functions* in Haskell take only one argument -
and multiple-argument functions just hide this by currying - the same must
apply to *types*; whereas in fact types *may* take multiple arguments?

On Sat, 19 Dec 2020, 13:02 David James, <dj112358 at outlook.com> wrote:

> Hello - some additional comments:
>
>
>
>    1. You should probably read this
>    <http://learnyouahaskell.com/higher-order-functions>, if you haven’t
>    already.
>
>
>
>    1. You can think of the declaration
>
> fmap :: (a -> b) -> [a] -> [b]
>
> as meaning: fmap takes two arguments:
>
> 1st arg of type (a -> b) (i.e.  a function, which takes one argument (of
> type a) and returns a result (of type b)).
>
> 2nd arg of type [a]
>
> and returns:
>
> a result of type [b]
>
>
>
> An example of a function that can be passed as the first argument would be
>
> Data.Char.ord :: Char -> Int
>
> If we pass this to map, we bind the type a to Char and the type b to Int.
> Then the second argument must be of type [Char], and the result will be
> of type [Int]. E.g.
>
> map Data.Char.ord ['F', 'r', 'e', 'd']
>
> gives
>
> [70,114,101,100]
>
>
>
>    1. Haskell allows “currying”. Which means all functions can be
>    “partially applied”. For example, we can apply map to only one
>    argument. E.g.
>
> map Data.Char.ord
>
> is partially applied, and has type
>
>                 [Char] -> [Int]
>
>                 You can see this by typing
>
> :t map Data.Char.ord
>
>
>
>                 (If you just type in
>
> map Data.Char.ord
>
> you will get an error, same as if you just typed in
>
>                 Data.Char.ord
>
> Haskell, reasonably, doesn’t know how to print a function)
>
>
>
> In fact, all function applications are curried, so even when you do
>
> map Data.Char.ord ['F', 'r', 'e', 'd']
>
> It actually applies the 1st arg to get a function of type [Char] -> [Int],
> to which it then applies the second arg to get the final value, which it
> prints. You could write it as this:
>
> (map Data.Char.ord) ['F', 'r', 'e', 'd']
>
>
>
> i.e. function application is left-associative. If you don’t put in the
> brackets to explicitly state differently, you effectively get brackets to
> the left. This is the same as e.g.
>
>                                 7 – 4 – 1
>
>                 meaning
>
>                                 (7 – 4) – 1
>
>                 which equals 2. It does not mean
>
>                                 7 – (4 – 1)
>
>                 which equals 4. If you want the latter, you need to
> explicitly write the brackets.
>
>
>
>                 You could of course write
>
> map (Data.Char.ord ['F', 'r', 'e', 'd'])
>
> This is syntactically valid, but would attempt to apply Data.Char.ord to
> the list of characters, which would give a type error. (And a second type
> error for attempting to apply map to the result of Data.Char.ord.
>
>
>
>    1. In type declarations function application is right-associative, so
>
> a -> b -> [a] -> [b]
>
> means
>
>                 a -> (b -> ([a] -> [b]))
>
> which represents a function of one argument (of type a), which returns a
> result of type (b -> ([a] -> [b])). I’m not sure it would be possible to
> write such a function, but it would certainly not be the same as map.
>
>
>
> If you want the brackets in a different place (and we do), then we need to
> put them explicitly, i.e.
>
> (a -> b) -> ([a] -> [b])
>
>                 Or, we could you the right-associative default to omit the
> second pair:
>
> (a -> b) -> [a] -> [b]
>
>
>
>    1. Note that the associativity is simply a matter of syntax. The
>    Haskell definition could have said you always need to put the brackets.
>    Then 7 – 4 – 1 would be a syntax error, you’d need to put either (7 – 4) –
>    1 or 7 – (4 – 1). However, many people find typing without brackets helpful
>    most of the time. (Though I must admit that I often “over-bracket” my code,
>    either because I’m not sure of the associativity of different operators, or
>    because I want to make the code more explicitly clear).
>
>
>
> Haskell has defined function application to be left-associative because of
> currying, as described above. Even though
>
> map Data.Char.ord ['F', 'r', 'e', 'd']
>
> looks like applying two arguments, it really does (map Data.Char.ord)
> first.
>
>
>
> Similarly, Haskell has defined functions in type declarations to be
> right-associative for the same reason. The function consumes the first arg
> first, so in
>
>                 (a -> b) -> [a] -> [b]
>
> after consuming the (a -> b), you’re left with a function of type ([a] ->
> [b]).
>
>
>
> Sorry, that ended up quite a bit longer than I expected, but I hope it
> helps and apologies if I’ve made any errors/etc.
>
>
>
> David.
>
>
>
> *From: *Lawrence Bottorff <borgauf at gmail.com>
> *Sent: *19 December 2020 03:37
> *To: *Bruno Barbier <brubar.cs at gmail.com>
> *Cc: *The Haskell-Beginners Mailing List - Discussion of primarily
> beginner-level topics related to Haskell <beginners at haskell.org>
> *Subject: *Re: [Haskell-beginners] map type explanation
>
>
>
> So in effect
>
>
>
> a -> b -> [a] -> [b]
>
>
>
> wants to be, would be
>
>
>
> a -> (b -> ([a] -> [b]))
>
>
>
> without the parens (which is a natural result of lambda calculus,
> perhaps?) -- which is not what is meant by map. But underlying a Haskell
> type declaration is currying, is it not? At the type declaration level,
> it's all currying, correct?
>
>
>
> Conceptually, I understand how the a -> b "event" needs to be a "package"
> to apply to the list [a]. The map function commandeers the target
> function (which alone by itself does some a -> b evaluation) to be a new
> object that is then applied to each member of list [a]. Good. So (a -> b)
> then is a notation that signifies this "package-ness".
>
>
>
> Does anyone have examples of other "packaging" where a function doing some a
> -> b is changed to (a -> b) ?
>
>
>
> On Fri, Dec 18, 2020 at 5:18 PM Bruno Barbier <brubar.cs at gmail.com> wrote:
>
>
> Hi Lawrence,
>
> Lawrence Bottorff <borgauf at gmail.com> writes:
>
> > Why is it not just
> >
> > a -> b -> [a] -> [b]
> >
> > again, why the parentheses?
>
> In Haskell, (->) is a binary operator and is right associative. If you
> write:
>
>    a -> b -> [a] -> [b]
>
> it implicitly means:
>
>    a -> (b -> ([a] -> [b]))
>
> So here, you need explicit parenthesis:
>
>    (a -> b) -> [a] -> [b]
>
> to mean:
>    (a -> b) -> ([a] -> [b])
>
> It's more about parsing binary operators than about types.
>
> Does it help ?
>
> Bruno
>
> > On Fri, Dec 18, 2020 at 4:10 PM Ut Primum <utprimum at gmail.com> wrote:
> >
> >> Hi,
> >>
> >> a -> b  is the type of a function taking arguments of a generic type (we
> >> call it a) and returning results of another type, that we call b.
> >>
> >> So
> >> (a -> b ) -> [a] -> [b]
> >> Means that you have a first argument that is a function (a-> b),  a
> second
> >> argument that is a list of elements of the same type of the function
> input,
> >> and that the returned element is a list of things of the type of the
> output
> >> of the function.
> >>
> >> Cheers,
> >> Ut
> >>
> >> Il ven 18 dic 2020, 23:02 Lawrence Bottorff <borgauf at gmail.com> ha
> >> scritto:
> >>
> >>> Thank you, but why in
> >>>
> >>> map :: (a -> b) -> [a] -> [b]
> >>>
> >>> are there parentheses around a -> b ? In general, what is the currying
> >>> aspect of this?
> >>>
> >>>
> >>> On Fri, Dec 18, 2020 at 12:43 PM David McBride <toad3k at gmail.com>
> wrote:
> >>>
> >>>> They are not parameters, they are the types of the parameters.
> >>>>
> >>>> In this case a can really be anything, Int, Char, whatever, so long as
> >>>> the function takes a single argument of that type and the list that is
> >>>> given has elements of that same type.
> >>>> It is the same for b, it doesn't matter what b ends up being, so long
> as
> >>>> when you call that function the function's return value is compatible
> with
> >>>> the element type of the list that you intended to return from the
> entire
> >>>> statement.
> >>>>
> >>>> You can mess with it yourself in ghci to see how type inference works.
> >>>>
> >>>> >:t show
> >>>> :show :: Show a => a -> String
> >>>> >:t map show
> >>>> map show :: Show a => [a] -> [String]
> >>>> > :t flip map [1::Int]
> >>>> > flip map [1::Int] :: (Int -> b) -> [b]
> >>>>
> >>>>
> >>>> On Fri, Dec 18, 2020 at 1:31 PM Lawrence Bottorff <borgauf at gmail.com>
> >>>> wrote:
> >>>>
> >>>>> I'm looking at this
> >>>>>
> >>>>> ghci> :type map
> >>>>> map :: (a -> b) -> [a] -> [b]
> >>>>>
> >>>>> and wondering what the (a -> b) part is about. map takes a function
> >>>>> and applies it to an incoming list. Good. Understood. I'm guessing
> that the
> >>>>> whole Haskell type declaration idea is based on currying, and I do
> >>>>> understand how the (a -> b) part "takes" an incoming list, [a] and
> >>>>> produces the [b] output. Also, I don't understand a and b very well
> >>>>> either. Typically, a is just a generic variable, then b is another
> >>>>> generic variable not necessarily the same as a. But how are they
> being
> >>>>> used in this type declaration?
> >>>>>
> >>>>> LB
> >>>>> _______________________________________________
> >>>>> Beginners mailing list
> >>>>> Beginners at haskell.org
> >>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
> >>>>>
> >>>> _______________________________________________
> >>>> Beginners mailing list
> >>>> Beginners at haskell.org
> >>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
> >>>>
> >>> _______________________________________________
> >>> Beginners mailing list
> >>> Beginners at haskell.org
> >>> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
> >>>
> >> _______________________________________________
> >> Beginners mailing list
> >> Beginners at haskell.org
> >> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
> >>
> > _______________________________________________
> > Beginners mailing list
> > Beginners at haskell.org
> > http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
>
>
> _______________________________________________
> Beginners mailing list
> Beginners at haskell.org
> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/beginners/attachments/20201219/b3e69b18/attachment-0001.html>


More information about the Beginners mailing list