Send Beginners mailing list submissions to beginners@haskell.org To subscribe or unsubscribe via the World Wide Web, visit http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners or, via email, send a message with subject or body 'help' to beginners-requ...@haskell.org
You can reach the person managing the list at beginners-ow...@haskell.org When replying, please edit your Subject line so it is more specific than "Re: Contents of Beginners digest..." Today's Topics: 1. Re: map type explanation (Josh Friedlander) ---------------------------------------------------------------------- Message: 1 Date: Sat, 19 Dec 2020 20:31:49 +0200 From: Josh Friedlander <joshuatfriedlan...@gmail.com> To: The Haskell-Beginners Mailing List - Discussion of primarily beginner-level topics related to Haskell <beginners@haskell.org> Subject: Re: [Haskell-beginners] map type explanation Message-ID: <cac2wd70hkg1z7ngkkndb9k+7oqxtm1pd9itzki6da1hyoms...@mail.gmail.com> Content-Type: text/plain; charset="utf-8" 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, <dj112...@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 <borg...@gmail.com> > *Sent: *19 December 2020 03:37 > *To: *Bruno Barbier <brubar...@gmail.com> > *Cc: *The Haskell-Beginners Mailing List - Discussion of primarily > beginner-level topics related to Haskell <beginners@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...@gmail.com> wrote: > > > Hi Lawrence, > > Lawrence Bottorff <borg...@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 <utpri...@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 <borg...@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 <toa...@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 <borg...@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@haskell.org > >>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners > >>>>> > >>>> _______________________________________________ > >>>> Beginners mailing list > >>>> Beginners@haskell.org > >>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners > >>>> > >>> _______________________________________________ > >>> Beginners mailing list > >>> Beginners@haskell.org > >>> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners > >>> > >> _______________________________________________ > >> Beginners mailing list > >> Beginners@haskell.org > >> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners > >> > > _______________________________________________ > > Beginners mailing list > > Beginners@haskell.org > > http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners > > > _______________________________________________ > Beginners mailing list > Beginners@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.html> ------------------------------ Subject: Digest Footer _______________________________________________ Beginners mailing list Beginners@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners ------------------------------ End of Beginners Digest, Vol 149, Issue 14 ******************************************