Arc Forumnew | comments | leaders | submitlogin
Changing function parameter order, and map
2 points by shader 3607 days ago | 11 comments
Is there any way to change the order of a functions arguments, temporarily, during run-time?

Or, how about "currying" a function so that all of the arguments but one are filled in, and you want to apply the function via map over a list, using the values of the list to fill in the last argument?

How does map work if you don't give the same number of values in each parameter list? Is it possible to make it so that if there are too few, it repeats the last one? Or maybe starts over at the beginning?

3 points by cchooper 3607 days ago | link

1. It depends what you mean by 'temporarily'? To change it in a local scope, you can shadow the function variable like this:

  (def foo (x y) (pr x y))

  (let foo (fn (y x) (foo x y)) (foo "one" "two"))
  => twoone
2. Square-bracket notation is the most concise way to partially apply a function to all but one argument:

  (map [foo _ "bar"] '(1 2 3))
  => 1bar2bar3bar
Currying is a different thing to partial application and isn't supported by Arc, but it is possible to write a curry operator that can produce the curried equivalent of any function. (Note that the 'curry' operator defined by pg in ANSI Common Lisp does not actually curry the function, strictly speaking). Such an operator would have to take an argument saying how many arguments the original function had, as Arc has no way of reflecting on functions at the moment.

3. map is currently implemented so that extra list members are simply ignored:

  (map + '(1 2 3) '(1 2))
  => (2 4)
It would be quite easy to define new versions of map that do what you require. For example, repeating the last element:

  (def repeat-map (f . ls)
    (if (pos no ls) nil
        (all ~cdr ls) (list:apply f (map car ls))
        (cons (apply f (map car ls)) 
              (apply repeat-map f (map [if (~cdr _) _ (cdr _)] ls)))))


2 points by shader 3607 days ago | link

Thanks, that was what I was looking for. Unfortunately, I think I've configured something wrong in git or ssh, and cannot clone the arc repo for actually using it ;)

By temporarily, I originally meant without defining a shadow function, like you did, just reorganizing them for the single call. But that might not be easy to do in a concise, flexible way so I suppose shadow functions make the most sense.

It seems awfully quiet around here.


2 points by cchooper 3607 days ago | link

You shouldn't need ssh just to clone the repo. This should work fine:

git clone git://

However, you can't push using that URL, so you'll end up with an un-pushable copy. Have you tried looking through all the guides?

To reorder arguments in a single call... it would certainly be easy to do that for binary functions:

  (def swap (f)
    (fn (x y) (y x)))

  ((swap foo) "foo" "bar")
  => barfoo
That's about the best I can do,

As for the silence, it appears almkglor and stefano are busy working on hl ( I don't know if they still read the forum. I suspect a lot of other people are getting disheartened.

Also, until there's another release of Arc, there isn't much to talk about.


1 point by shader 3606 days ago | link

Yes, I think I've followed all of the guides. However, I keep getting the "Permission (publickey)" error. I wonder if there are more configurations like username or email address that have to be the same as what github expects?


2 points by cchooper 3607 days ago | link

And here's a function that performs true currying on a function:

  (def curry (f n (o args nil))
    (if (is 0 n) (apply f (rev args))
        (fn (x) (curry f (- n 1) (cons x args)))))
An example of usage:

  (subst "bar" "foo" "catfood")
  => "catbard"

  (= curried-subst (curry subst 3))

  (((curried-subst "bar") "foo") "catfood")
  => "catbard"


1 point by shader 3607 days ago | link

What if you wanted to curry the function in a different order? :)

I suppose you would just curry a shadow function? Or could a utility/macro be made to easily map one order of parameters to another?


1 point by cchooper 3607 days ago | link

The problem is: what's a concise way of expressing the new order? Perhaps something like this:

  ((reorder foo (x y z) (z x y)) 1 2 3)
but it's so clunky it's not really worth it. If you could reflect on functions to see their parameter list, then you could do this:

  (def foo (x y z) ...stuff...)

  ((reorder foo (z x y)) 1 2 3)
A little better.


2 points by Darmani 3607 days ago | link

May give you a few ideas:


1 point by cchooper 3606 days ago | link

Ah yes, cycle notation!

  ; convert a cycle into transpositions
  (def trans (cycle (o first nil))
    (if (no cycle) nil
        (~cdr cycle) (list:list cycle.0 first)
        (cons (list cycle.0 cycle.1)
              (trans (cdr cycle) 
                     (if first first cycle.0)))))

  ; permute a list using a list of disjoint cycles
  (def permute (cycles l)
    (with (ts (apply join (map trans cycles))
           ret (copy l))
      (map [= (ret (- _.1 1)) (l (- _.0 1))] ts)

  (permute '((1 2 3) (4 5)) '(a b c d e))
  => (c a b e d)


2 points by shader 3606 days ago | link

hmm. I think that cycle notation is sometimes shorter than just stating the final positions, but only rarely.

How about a function that does:

  >(reorder '(2 5 4 1 3) '(a b c d e))
  '(b e d a c)
That makes more sense in many cases. But having a function that does permutations using cycle notation is probably also useful.


2 points by rntz 3607 days ago | link

Yes, all of these can be done.

    (def flip (f) (fn (a b) (f b a)))
    (def curry (f x) (fn a (apply f x a)))
The last has been done by cchooper already. 'flip is actually defined in lib/util.arc on anarki; I find it useful when doing folds and the like.

Edit: apparently all of the above has been posted already :-(. Please excuse the noise.