Arc Forumnew | comments | leaders | submitlogin
Haskell-like currying and reversed currying
11 points by rincewind 5977 days ago | 2 comments

  Arc            Haskell
  (f a b)        f a b
  [f a _]        f a         Haskell version returns a function because of implicit currying
  ((f a b) c)    f a b c     Applies (f a b) to c
In Haskell this works because of implicit currying, fixed-arity-functions and left-associative function application. There were already some currying functions and macros discussed in this forum.

The "reverse currying" behaviour can also be achieved in Arc if the arity of a function is known. E.g. if f takes two arguments, (f a b c) can unambiguously be interpreted as ((f a b) c). This does not affect normal currying, so (f a) means [f a _].

  ;implementation of currying
  (def curry (arity fun)
   (fn args
       (if (is arity len.args)
             (apply fun args)
           (< len.args arity)
              (curry (- arity len.args) 
                 (fn args2 (apply fun (join args args2))))
           (> len.args arity)
             (apply (apply fun (firstn arity args)) 
                (nthcdr arity args)))))

  (zap [curry 2 _] curry)

  ;some examples
  (= add (curry 2 +))
  (= add2 (curry.2 map (add 2)))

  (add2 (list 1 2 3))
  ;returns (3 4 5)

  (map (curry.2 + 4) (list 1 2 3))
  ;returns (5 6 7)

  ;useful application of the concept:
  ;nested structure access withoud nested parantheses
  (mac rc-obj args `(annotate 'rc-obj (obj ,@args)))

  (defcall rc-obj args
         (apply (curry.2 (fn (t k) t.k)) args))

  (= tabl 
     (rc-obj tom (rc-obj age 28 
                    eyecolor 'green 
                    father (rc-obj name 'harry 
                                   age '54 
                                   eyecolor 'blue)) 
             dick (rc-obj age 45 
                          eyecolor 'brown)))

  (tabl 'tom 'father 'age)
  ;returns 54


6 points by drcode 5976 days ago | link

First of all, this is a nice piece of work, rincewind- I'm going to have to think a while to decide on the merits of this approach for my personal use. I like the fiendish use of 'zap :-)

FYI- If any of you are confused by the extra 2 in rincewinds code, it is NOT one of the numbers to be added. The currying code just requires it because of the impedance mismatch between variable arguments and currying. The Haskell core doesn't have variable argument support, so this is not an issue in Haskell.

Keep in mind that "On Lisp" covers currying, whereas arc currently does not. I assume this is because pg is still trying to decide on a currying approach, whether it will be implicit currying, syntax-based currying, or function-based currying.

Here's an awesome variant based on your approach I'm probably going to try and implement soon, now that I've thought of it- Have a number in the function position (currently an error) initiate currying!

For example:

  > (2 +)
  #<procedure>
The two here, as in rincewind's code, means that the curried version of '+ should resolve to the result after two parameters are passed in.

  > ((2 +) 7)
  #<procedure>

  > (((2 +) 7) 5)
  12

  > (map ((2 +) 7) '(1 2 3))
  (8 9 10)

  > (map (2.+ 7) '(1 2 3))
  (8 9 10)

  (these next ones assume my mods to the intrasymbol syntax are in place http://arclanguage.org/item?id=7644)

  > (map 2.+.7 '(1 2 3))
  (8 9 10)

  (for those of you wondering why the "2" is necessary)

  > (map 3.+.7 '(1 2 3))
  (#<procedure> #<procedure> #<procedure>)

  > (map [_ 100] (map 3.+.7 '(1 2 3)))
  (108 109 110)
Note that the "integers in function position" concept could also work with implicit currying- In that case, "2.+" would simply convert '+ into the dual arity version of '+. The examples would stay the same- However, in that case the integer could of course be ommited for fixed arity functions.

-----

4 points by almkglor 5976 days ago | link

Cool ^^ The number is jarring especially in a mathematical context but ultimately necessary, since we cannot detect the arity of functions.

Arc has absolutely no axioms for introspecting into function objects - it can only detect if the object is a function, and nothing else. I hope to rectify this in the Arc dialect I'll build for SNAP - there should be a ways to decompose a function to a function code object (potentially serializable!) and the closured data, as well as determine other bits about the function.

-----