Loading ...
Sorry, an error occurred while loading the content.

Thoughts on currying

Expand Messages
  • daniel_yokomiso
    Hi, I was thinking about currying recently because I was trying to come up with a syntax that supported optional, positional and named parameters cleanly, and
    Message 1 of 4 , Sep 1, 2003
    • 0 Attachment
      Hi,

      I was thinking about currying recently because I was trying to
      come up with a syntax that supported optional, positional and named
      parameters cleanly, and currying kept making things hard. And curry
      just works with the first parameter. In Eon (my language) we can
      currently write:

      list map (2 +)

      To send the map message to list, it'll return a closure that
      consumes an one-parameter function and returns a list, or with
      parenthesis:

      (((list) map) (2 +))

      So "(list)" has type "Integer List", "((list) map)" has type
      "(Integer -> b) -> (b List)" and "(2 +)" has type "Integer -> Integer".
      This implicit currying is similar to Haskell and ML, but it makes
      the usual usage (a method call with all know parameters) a special
      case of the most general curry-then-give-closure method. Also it makes
      easy to write "list map (2 /)" but makes "list map (\x -> x / 2)" a
      special case because the order of the division.
      This lead me to the following syntax:

      list map (2 + _)

      Where we have to explicitly state the non-curried parameter ("_").
      This would make easy to state what you want to write:

      Sugared Version: Expanded Version:
      list map (2 + _) list map [\ x -> 2 + x]
      list map _ [\ f -> list map f]
      _ map (2 + _) [\ l -> l map [\ x -> 2 + x]]
      list map (_ + _) list map [\ x -> [\ y -> x + y]]

      and just "list map" would be an invalid expression.

      My question is: Is this kind of feature interesting in a language,
      or most FPL users would find painful to explicit state the non-curried
      parameters? Also today my parser can create the parse tree without
      having to understand function's interfaces. In this new form the
      parser would just create some token lists for expressions and only
      after reading the function's interfaces it would be able to form the
      expressions' parse trees.

      Best regards,
      Daniel Yokomiso.
    • Marcin 'Qrczak' Kowalczyk
      ... The left side is how it looks like in my language, except it would be map list instead of list map . Here is what I ve written about currying ... I do
      Message 2 of 4 , Sep 1, 2003
      • 0 Attachment
        Dnia pon 1. września 2003 19:05, daniel_yokomiso napisał:

        > Sugared Version: Expanded Version:
        > list map (2 + _) list map [\ x -> 2 + x]
        > list map _ [\ f -> list map f]
        > _ map (2 + _) [\ l -> l map [\ x -> 2 + x]]
        > list map (_ + _) list map [\ x -> [\ y -> x + y]]

        The left side is how it looks like in my language, except it would be
        "map list" instead of "list map". Here is what I've written about currying
        and this syntax on comp.lang.misc:

        --------
        Ed Avis wrote:

        > But I don't see any reason to ditch currying in a language where function
        > application is written with juxtaposition - it seems the simplest way to
        > give multiple arguments.

        I do see. Without currying the function can determine how many arguments it
        received. Especially in a dynamically typed language there is no reason to
        not allow to call the same functions with varying number of arguments.

        Also it makes errors more easily detected, again especially in a
        dynamically typed language. Without currying the language can precisely
        say that there are too few or too many arguments instead of producing a
        value of a wrong type.

        It happens that my language uses the syntax "f a b" and no currying. For
        zero arguments it's "f()" - in a non-pure language it makes sense to talk
        about an application to no arguments.

        It's also easier to implement. Even with currying you want to implement
        application to several arguments without materializing all the intermediate
        partial applications.

        > I think I would prefer naming the placeholders
        >
        > f $1 a $2 b = \ x y -> f x a y b
        >
        > This lets you change the order around, so (g $2 $1) would be a version
        > of g that takes arguments in the other order.

        For more complicated expressions you need an explicit lambda anyway. If its
        parameters are used deeper than as arguments of its top-level application,
        then it's not clear where would you insert the implicit lambda. So since it
        covers only simple common cases, it's enough for me to just mark "open"
        arguments without numbering them. I use _ for that.
        --------

        And from a followup:
        --------
        > For just one open argument per expression, or several? Can you give
        > an example?

        Several, but I haven't needed to use more than one yet.
        "f a _ b _ _ c" is "? x y z {f a x b y z c}" (? = lambda).

        I'm not sure whether it's better to evaluate the supplied arguments at the
        point of creation of the function or each time it is applied. Sometimes we
        may want one or the other, and usually (in the truly functional style) it
        doesn't matter except perhaps performance. Currently I evaluate them when
        the function is created, because:

        a) It can be thought of like currying, i.e. supplying some arguments now
        and waiting for the rest - rather than like rewriting the source syntax
        to insert a lambda.

        b) IMHO more often you prefer to evaluate them once. If you want each time,
        you can insert an explicit lambda.

        c) The syntax doesn't use {} like general anonymous functions do, so I hope
        it's clear that arguments aren't "protected" by {} and thus deferred.

        In function headers you can write paramName... for the rest of parameters
        packed in a list - anywhere, but at most once; and similarly when applying
        a function or writing a list inside [] - here possibly multiple times. So
        you can use _... as an argument of an application with the obvious meaning,
        e.g. "f x _..." partially applies the first argument no matter how many
        there are.
        --------

        > or most FPL users would find painful to explicit state the non-curried
        > parameters?

        I don't know.

        For me in a dynamically typed setting the ability to check too few or too
        many arguments at all (since it generally can't be done at compile time),
        and the ability pass an unknown number of arguments, outweigh the compact
        syntax of currying and the nice property that you can think about a
        function returning a function or about a two-parameter function and it
        boils down to the same. In such case I found convenient to have the _
        shortcut besides lambda, to overcome lack of currying.

        In a statically typed language currying is more attractive. The type system
        usually allows the compiler to report an error about an incorrect number
        of arguments, and even with currying it can give a helpful message
        suggesting that this is the cause when a function type is unified with a
        non-function type. Variable number of arguments doesn't mix well with
        static typing anyway.

        In Haskell operators are all binary (except -) and they can be partially
        applied on either argument: (/2) and (1/). A named function can be turned
        into a binary operator `thus` and also partially applied.

        > Also today my parser can create the parse tree without
        > having to understand function's interfaces. In this new form the
        > parser would just create some token lists for expressions and only
        > after reading the function's interfaces it would be able to form the
        > expressions' parse trees.

        This must be some unfortunate combination of features. I certainly don't
        need to know the signature to parse a call. Conceptually a function is
        always applied to a list of arguments of statically unknown size; it's up
        to the function to signal an error when there are too few or too many.

        --
        __("< Marcin Kowalczyk
        \__/ qrczak@...
        ^^ http://qrnik.knm.org.pl/~qrczak/
      • Daniel Yokomiso
        ... From: Marcin Qrczak Kowalczyk To: Sent: Monday, September 01, 2003 5:30 PM Subject: Re: [langsmiths]
        Message 3 of 4 , Sep 1, 2003
        • 0 Attachment
          ----- Original Message -----
          From: "Marcin 'Qrczak' Kowalczyk" <qrczak@...>
          To: <langsmiths@yahoogroups.com>
          Sent: Monday, September 01, 2003 5:30 PM
          Subject: Re: [langsmiths] Thoughts on currying

          > Dnia pon 1. wrzesnia 2003 19:05, daniel_yokomiso napisal:
          >
          > > Sugared Version: Expanded Version:
          > > list map (2 + _) list map [\ x -> 2 + x]
          > > list map _ [\ f -> list map f]
          > > _ map (2 + _) [\ l -> l map [\ x -> 2 + x]]
          > > list map (_ + _) list map [\ x -> [\ y -> x + y]]
          >
          > The left side is how it looks like in my language, except it would be
          > "map list" instead of "list map".

          My language uses a pos/infix, OO-like, notation for method calls. It's
          usually easier to write long expressions.

          [snip]

          Wasn't that a thread that included comp.lang.functional too? IIRC it started
          with some about language power or somesuch, I saw some of the posts, but
          quickly ignored them.

          So you use this notation because your language is dynamically-typed. Eon is
          statically-typed, so perhaps it won't be so helpful as it is to you, but I
          think that it'll be "prettier".

          Just a thought, you use "f _ x _ y" but "f $2 x $1 y" to the ordered
          parameters, wouldn't be better to use "f _2 x _1 y" instead?

          [snip]

          > > Also today my parser can create the parse tree without
          > > having to understand function's interfaces. In this new form the
          > > parser would just create some token lists for expressions and only
          > > after reading the function's interfaces it would be able to form the
          > > expressions' parse trees.
          >
          > This must be some unfortunate combination of features. I certainly don't
          > need to know the signature to parse a call. Conceptually a function is
          > always applied to a list of arguments of statically unknown size; it's up
          > to the function to signal an error when there are too few or too many.

          As I said above my language uses a pos/infix notation, so in Haskell someone
          would write:

          map g (filter p (map f xs))

          While in Eon you can write:

          xs map f filter p map g

          necause with left to right evaluation the compiler knows how to parse the
          call:

          ((xs map f) filter p) map g

          Also as objects are functions from symbols to bound-functions, it was just a
          normal curried expression. Now if I drop currying, either I'll be forced to
          explicit put the parenthesis (which I wanted to avoid in the first) use some
          kind of low precedence primitive operator (because all operators (except
          primitives as :=, :, etc.) have the same precedence) like Haskell's "$" or
          delay the parse tree definition to a third fase, after lexing and parsing.
          I'll probably follow this last choice and burden the compiler instead of the
          programmer.

          > --
          > __("< Marcin Kowalczyk
          > \__/ qrczak@...
          > ^^ http://qrnik.knm.org.pl/~qrczak/

          Best regards,
          Daniel Yokomiso.

          "I am not a vegetarian because I love animals; I am a vegetarian because I
          hate plants."
          - A. Whitney Brown


          ---
          Outgoing mail is certified Virus Free.
          Checked by AVG anti-virus system (http://www.grisoft.com).
          Version: 6.0.514 / Virus Database: 312 - Release Date: 28/8/2003
        • cr88192
          ... I will state that I largely agree with you in general. in my case I don t have currying, mostly because I couldn t think of a good reason to implement it
          Message 4 of 4 , Sep 1, 2003
          • 0 Attachment
            > <major snip>

            I will state that I largely agree with you in general.

            in my case I don't have currying, mostly because I couldn't think of
            a good reason to implement it (and forgo just using nested lambda's,
            if I actually needed to do it anyways...).

            my lang is dynamically typed, and I much more largely rely on
            variable numbers of arguments and pattern matching, and I am not sure
            these would mix that well with currying in general...

            if I wanted what could be possible in my case would be a macro that
            would silently transform the curried function into a nested lambda.

            eg:
            (define foo (c-lambda (x y z) (+ x y z)))

            c-lambda in this case would expand to:
            (lambda (x) (lambda (y) (lambda (z) (+ x y z))))

            (((foo 1) 2) 3) => 6

            of course:
            (foo 1 2 3)
            would be invalid...

            I know this is very crude.

            well, anyways...
          Your message has been successfully submitted and would be delivered to recipients shortly.