Arc Forumnew | comments | leaders | submitlogin
How do optional args work for innner args not passed in?
3 points by thaddeus 5537 days ago | 9 comments
Another question from the noob gallery:

    (def the-example (value1 (o value2 "wahoo!")
                     (o value3 "ugh!")(o value4 "omg!"))
        (prn "Value1: " value1)
        (prn "Value2: " value2)
        (prn "Value3: " value3)
        (prn "Value4: " value4)
     )
I was kinda hoping passing nil in for value2 would mean the function would use the default parameter for the argument.

but nope:

arc> (the-example "Results" nil "wowser!" "cha-ching!!!")

     Value1: Results
     Value2: nil
     Value3: wowser!
     Value4: cha-ching!!!
How does one do this without writing a bunch of clutter code conditional statements to handle nils ? Can it be done?

Also .... one more quick question: is it possible to have a prn statement embedded into an html output function that only outputs to the terminal not the browser ? I'm sooo tired of adding and removing test statements from the function. hehe :)

I hope that last question made sense....

Thanks, T.



2 points by fallintothis 5537 days ago | link

What it seems you want is keyword parameters, which Arc has forfeited. e.g., in Common Lisp

  (defun the-example (value1 &key (value2 "a") (value3 "b") (value4 "c"))
    (format t "Value1: ~a~%Value2: ~a~%Value3: ~a~%Value4: ~a~%"
              value1
              value2
              value3
              value4))

  > (the-example "Results" :value2 "foo" :value4 "bar")
  Value1: Results
  Value2: foo
  Value3: b
  Value4: bar
This is not to say Arc's exclusion of keyword parameters is without merit. e.g., Arc's (rreduce ...) is easier to read than Common Lisp's (reduce ... :from-end t). Maybe you could consider breaking your problem function up into several functions? This isn't always applicable, though, and can result in code duplication. You could resort to passing an alist or table as the last parameter. This is still clunky as all hell, so you could instead macro the process out a bit. For inspiration (and, moreover, code) on such a macro, check http://arclanguage.org/item?id=4247

-----

2 points by thaddeus 5537 days ago | link

omg! It's going to take me a while to read kenny's dsb macro stuff....... my brain just exploded doing a cursory glance.

Thanks for the info. T.

-----

2 points by thaddeus 5536 days ago | link

In retrospect, after doing some reading, I like the keywords concept outlined in kenny's dsb function. Although or=, works and I will use for now... in the long run I can see how having the sequence of arguments forced leading to bugs.

If I have many function calls all using an enforced sequence and for whatever reason the original function is changed (ie an inserted argument in the sequence list) all the function calls would have to be changed to accomodate.

The keyword concept also makes the code much more readable for the function calls: something like:

    (def the-example ((o car "mustang") (o year "1969") (o color "black")) 
         (prn "Car: " car)
         (prn "Year: " year)
         (prn "Color: " color)
    )
thus...

    (the-example car: camaro color: red year: 1968 )
is not only much more readable, but also the fact that I switched the order wouldn't impact the integrity of the code.

Additionally or=, prevents one from passing in nil as a valid argument...

probably stuff everyone here knows, but just my two cents!

.... actually in thinking about it.... I wonder if it was an intentional decision by pg not to put this feature in or was it just not gotten to?....

anyway - have a good night all, and thanks for the replies.

T.

-----

1 point by thaddeus 5528 days ago | link

So when I originally made this posting I was attempting to create a function that would create the style attributes within in an html div.

Since the style parameters/arguments are completely differrent for each of my divs, I found it a pain to keep doing this:

    (pr "<div " "id=")
	(write (string "divLeftBox"))  
	(pr "style=")
    (write (string "position: absolute; left: 1px; top:" 1 "px;" 
	(if (is border->toggle 1)(string "border: 1px solid #ff9000;"))
	 "width:" width "px; " "height: " height "px;"))
	(pr ">")
So I took a stab at writing a function, following, that would handle all the possible formats, but discovered the variances too ugly in coding without being able to handle the "inside optional arguments" for a function:

     (def genstyle-old (overflow position top right bottom left width width-uom height height-uom border-width border-color)
              (or= overflow 'auto)
	          (or= position 'absolute)
	          (or= top 0)
	          (or= right 0)
	          (or= bottom 0)
		      (or= left 0)
			  (or= width 100)
              (or= width-uom "%")
			  (or= height 100)
              (or= height-uom "%")
			  (or= border-width 1)
		      (= border-line-style 'solid)
			  (or= border-color "#ff9000")
              (string "overflow: " overflow ";" " position: " position ";"
                             " top: " top "px;" " right: " right "px;" " bottom: " bottom "px;" " left: " left "px;"
                             " width: " width width-uom ";" " height: " height height-uom ";" 
	                         " border: " border-width "px" " solid " border-color ";")
    )
Anyway that turned out too ugly and Kenny's dsb function was too complicated for me to figure out, so I went back and looked into how pg was doing these type of things... and came up with the following:

    (mac genfn args (genlist args))

    (def genlist (spec)
       `(tostring ,@(parg (pair spec)))
    )


    (def parg (options)
       (if (no options)
        nil
       (let ((opt val) . rest) options
            (cons (parg-it opt val)
                  (parg rest))))
    )

    (def parg-it (key val)
        `(aif ,val (pr " " ',key " " it ";"))
    )

this allows me to do this:

     (def test ()
         (= height 10) 
         (= width 20)
         (gentag div id "mydiv" style (genfn position: "absloute" overflow: "auto" width: (string width "px") height: (string height "px") padding: "2px 3px 2px 3px"))
     )
resulting in this:

    arc> (test)
    <div id="mydiv" style=" position: absloute; overflow: auto; width: 20px; height: 10px; padding: 2px 3px 2px 3px;">
* note the significance for me is that I can pull the style arguments from a table and then autogenerate the list to be passed into the genfn function based upon which attributes exist in the table; then all I would need to do is pass in the table name. The end result will be 1 function that generates all of my divs, table driven.

I figured there might be some people out there (like myself) trying to do the same thing. I don't know how to put things on "git", nor do I want to throw my "hacks" into a repository that's probably intended for better code. :)

T.

-----

1 point by absz 5537 days ago | link

To answer your last question, I think that printing to stderr instead of stdout won't show up in the browser; you can use the builtin ero or the following two functions to do so

  (def pre args
    " Like `pr', but writes to stderr.
      See also: [[prne]] [[pr]] [[ero]] "
    (w/stdout (stderr) (apply pr args)))
  
  (def prne args
    " Like `prn', but writes to stderr.
      See also: [[pre]] [[prn]] [[ero]] "
    (w/stdout (stderr) (apply prn args)))

-----

1 point by thaddeus 5537 days ago | link

awesome! thanks. T

-----

4 points by rincewind 5537 days ago | link

  (or= value2 'wahoo)

-----

2 points by thaddeus 5537 days ago | link

That does it.... Thanks, T.

    (def the-example (value1 value2 value3 value4)
         (or= value1 'Results)
         (or= value2 'wahoo!)
         (or= value3 'ugh!)
         (or= value4 'omg!)
         (prn "Value1: " value1)
         (prn "Value2: " value2)
         (prn "Value3: " value3)
         (prn "Value4: " value4)
)

-----

3 points by absz 5536 days ago | link

You could also wrap your or= sequence in a macro:

  (mac defaults args
    `(do ,@(pair args (fn (var val) `(or= ,var ,val)))))
  
  (def the-example (value1 value2 value3 value4)
    (defaults value1 'Results
              value2 'wahoo!
              value3 'ugh!
              value4 'omg!)
    (prn "Value1: " value1)
    (prn "Value2: " value2)
    (prn "Value3: " value3)
    (prn "Value4: " value4))

-----