Arc Forumnew | comments | leaders | submitlogin
3 points by lojic 6160 days ago | link | parent

Currying

Partial application

Pattern matching

Guards



2 points by pg 6160 days ago | link

Can you give me some examples of code that ends up being shorter with these things?

-----

7 points by almkglor 6160 days ago | link

  (def pair (xs (o f list))
    " Applies pairs of elements to the function `f'.
      See also [[tuples]] [[map]] "
    (if (no xs)
         nil
        (no (cdr xs))
         (list (list (car xs)))
        (cons (f (car xs) (cadr xs))
              (pair (cddr xs) f))))

  (defpat *defpat-pair
          " Example/testcase for defpat in redefining
            the `pair' function. "
          ((x y . zs))    `((,x ,y) ,@(*defpat-pair zs))
          ((x y . zs) f)  `(,(f x y) ,@(*defpat-pair zs f))
          ((x) . _)       `((,x))
          (() . _)        ())

-----

7 points by almkglor 6160 days ago | link

  (def map1 (f xs)
    " Return a sequence with function f applied to every element in sequence xs.
      See also [[map]] [[each]] [[mappend]] [[maps]] [[andmap]] [[ormap]] "
    (if (no xs)
        nil
        (cons (f (car xs)) (map1 f (cdr xs)))))

  (defpat map1-pat
     (_ ())        ()
     (f (x . xs))  (cons (f x) (map1 f xs)))

-----

3 points by pg 6160 days ago | link

Do you have an example of a function you might write in an application, rather than the definition of one of the basic list traversal operators? As I said in the Arc Challenge, pattern-matching looks great when it's used for those, but tends not to be so useful in applications, precisely because operations like map, once they're defined, give you so much of what you need from pattern matching.

-----

3 points by almkglor 6160 days ago | link

I wanted to use this as an example, but I suspect there's a bug when typ == 'choice - what's (cadr 'choice) ?

  (def varline (typ id val)
    (if (in typ 'users 'syms 'toks 'bigtoks)  (apply prs val)
        (is typ 'lines)                       (map prn val)
        (is typ 'yesno)                       (pr (if val 'yes 'no))
        (is typ 'choice)                      (varline (cadr typ) nil val)
        (text-type typ)                       (pr (or val ""))
                                              (pr val)))

-----

2 points by pg 6160 days ago | link

Oops, yes, you're right. I think that test should be (caris type 'choice).

-----

2 points by almkglor 6160 days ago | link

  (def varline (typ id val)
    (if (in typ 'users 'syms 'toks 'bigtoks)  (apply prs val)
        (is typ 'lines)                       (map prn val)
        (is typ 'yesno)                       (pr (if val 'yes 'no))
        (caris typ 'choice)                   (varline (cadr typ) nil val)
        (text-type typ)                       (pr (or val ""))
                                              (pr val)))

  (defpat varline-pat
    (,(typ (in typ 'users 'syms 'toks 'bigtoks))
        _ val)
         (apply prs val)
    ('lines _ val)
         (map prn val)
    ('yesno _ val)
         (pr (if val 'yes 'no))
    (('choice c) _ val)
         (varline c nil val)
    (,(typ (text-type typ)) _ val)
         (pr (or val ""))
    (_ __ val)
         (pr val))

-----

2 points by almkglor 6160 days ago | link

Might probably be shorter if I also add ,@(test _):

  (defpat varline-pat
    (,@(in _ 'users 'syms 'toks 'bigtoks)
        _ val)
         (apply prs val)
    ('lines _ val)
         (map prn val)
    ('yesno _ val)
         (pr (if val 'yes 'no))
    (('choice c) _ val)
         (varline c nil val)
    (,@(text-type _) _ val)
         (pr (or val ""))
    (_ __ val)
         (pr val))
The above won't work on nex-3's arc-wiki.git yet, but I'll add it this evening; I don't have access to my hacking computer right now.

-----

4 points by almkglor 6160 days ago | link

  (def eschtmlchar (c)
    (case c
       #\<  "&lt;"
       #\>  "&gt;"
       #\&  "&amp;"
            (string c)))

   (defpat eschtmlchar-pat
     (#\<)  "&lt;"
     (#\>)  "&gt;"
     (#\&)  "&amp;"
     (c)    (string c))

-----

7 points by almkglor 6160 days ago | link

  (def rev (xs)
    " Reverses a sequence. "
    ((afn (xs acc)
       (if (no xs)
           acc
           (self (cdr xs) (cons (car xs) acc))))
     xs nil))

  (defpat rev-pat
     (x)            (rev-pat x nil)
     ((x . xs) acc) (rev-pat xs (cons x acc))
     (()       acc) acc)

-----

3 points by lojic 6160 days ago | link

I've only read a bit and dabbled myself. I particularly liked the currying and partial application that I saw in Haskel. It just seemed like a fundamentally good idea to me. Possibly even axiomatic. The impression I got was that it added power in flexibility of function composition.

Regarding pattern matching & guards, I have even less experience with that, but the functional folks are certainly enamored with them. There was a thread on comp.lang.lisp regarding a symbolic simplifier that was apparently much more concise with pattern matching.

Hopefully some functional experts will come along to articulate the benefits.

-----

4 points by cooldude127 6160 days ago | link

partial application is something I always miss in lisp. I often find myself writing anonymous functions that would be much shorter with partial application. here are a few examples from some of my own CL code (pay attention to the second let binding):

With anonymous function

  (defmethod do-step ((w world))
    (let* ((locs-to-check (all-cells w))
           (actions (mapcar (lambda (x) (act w x)) locs-to-check)))
      ...)
With an explicit curry macro:

  (defmethod do-step ((w world))
    (let* ((locs-to-check (all-cells w))
           (actions (mapcar (curry act w) locs-to-check)))
      ...)
The way it should be (built into the language):

  (defmethod do-step ((w world))
    (let* ((locs-to-check (all-cells w))
           (actions (mapcar (act w) locs-to-check)))
      ...)
It might seem small, but do it enough times and you appreciate the succinctness.

-----

4 points by raymyers 6158 days ago | link

I also enjoy currying and "pointfree" style. However, wouldn't it require giving up functions that take an arbitrary number of arguments? (In fact Scala has both, but it required introducing a special syntax.)

I find that Arc's shortcut closure [] notation is a surprisingly good curry-substitute. For example:

    (map (act w) locs-to-check) ; currying
    (map [act w _] locs-to-check) ; only one token longer

-----

2 points by cooldude127 6158 days ago | link

there's something to that. i didn't really think about it, but that might just be fine. that's actually exactly what scala's explicit partial application looks like, with the underscore.

i honestly haven't been doing a whole lot of practical arc programming. CL and Slime have spoiled me to the point where I find it difficult to use a language that doesn't have that convenience

-----