Arc Forumnew | comments | leaders | submit | CatDancer's commentslogin
2 points by CatDancer 6203 days ago | link | parent | on: New Version of Arc

I'll be posting my hacks to arc3 in a day or two ^_^

-----


I tried to uncompress and upload a copy of the original Postscript version of the paper (http://people.csail.mit.edu/alan/ftp/pepm99.ps.gz) to scribd, but the result had a quite unreadable font.

Along with pg's writings, this paper is another description of how the synergy between Lisp code and quasiquotation makes it easy to do code generation such as macros.

The paper also has a nice explanation of how to nest quasiquote expressions.

-----

1 point by CatDancer 6206 days ago | link | parent | on: Example: Rewriting the login code

I notice the code to have the login result in either an html page or a redirect is somewhat awkwardly distributed between login-form (through fnform) and the login function itself.

I found it helpful to make a base op in srv.arc which outputs no headers, and then my login function was able to itself either output a page, or call a function named redirect with the url which outputs the redirect headers.

-----

1 point by CatDancer 6206 days ago | link | parent | on: Arc presentation

This will be fixed in the next release of Arc (http://arclanguage.org/item?id=9163)

-----

1 point by CatDancer 6206 days ago | link | parent | on: Any other arc news forums out there?

Your ProxyPass command is the one I was using with Apache.

Anything in the Apache error log?

Also, are you able to get to port 8080 on the box? I.e.

  curl -v -s http://localhost:8080/

-----

1 point by thaddeus 6202 days ago | link

Ok so after getting an arc3 forum, running on linode - using proxypass I notice I am getting periodic 502 proxy errors.

Also I found this old post that claims that these timeouts are a side effect of the 'date' problem that Anarki had fixed, but in Arc3 pg fixed the date function so i am guessing this wouldn't be the issue?

http://arclanguage.org/item?id=4728 http://arclanguage.org/item?id=4714

any ideas ?

Thanks, T.

-----

1 point by CatDancer 6202 days ago | link

Anything in the Apache error log about what it doesn't like about the response it's getting from the Arc web server?

Oh and if you hit your forum directly at the 8080 (or whatever) port do you have any similar problems?

-----

1 point by thaddeus 6202 days ago | link

Good idea - I should have done that.

I am proxy passing from port80 to 3 different ports for 3 different domains (each running it's own arc server). Looks like the calls are getting mixed up.

ie. mydomain1.com, mydomain2.com, mydomain3.com

looks like mydomain1.com should be calling

    mydomain1.com/public/favicon.ico
but instead it's getting passed to mydomain2.com

File does not exist: ....mydomain2.com/public/favicon.ico

hmmm. There must be a better way to keep the pointers in order. Back to google :)

T.

-----

1 point by thaddeus 6201 days ago | link

well i think it's fixed.

I just changed:

  favicon-url*  "" to  ->  favicon-url*  "logo.gif"
I'm hazarding guess, but I think when apache can't find a file via the arc servers static directory apache attempts to find it using anyone if not all of the public directories listed in the virtual hosts.

strange, but anyway - thanks for trying to help Cat, sorry to be a pain - this was my first time installing apache, linux or doing any of this stuff :).

T.

-----

1 point by thaddeus 6206 days ago | link

Thanks Cat,

I did manage to figured it out... I had to add the proxy_http module. T.

-----


Ah, I think there's another idea in here trying to get out that I haven't articulated.

If I'm writing a library function that provides access to some MzScheme functionality, then some bridging code needs to be written. In arc2, that bridging code is necessarily written in Scheme in order to implement Arc. However, once Arc is up and running, since I prefer to write in Arc over Scheme, I'd rather write that bridging code in Arc.

This bridging code is something I write very infrequently. And, someone who wanted to use my library function wouldn't need to look at the bridging code at all if they didn't want to.

From a kind of "Huffman coding" perspective we want symbols that are used a lot to be short (as long as they are still readable). Conversely we don't want valuable short symbols to be reserved for things that we don't have to type very often. This is why I don't like the naming of Anarki's "$" macro, not because I don't think that being able to evaluate a bit of Scheme code isn't valuable or important, but because such evals will usually be quickly encapsulated in some library function and I think that a symbol such as "$" to too rare and valuable to be used for something that just doesn't need to be typed very often.

Suppose the feature were named, I don't know, say "ac-passthru" or something. This would be no burden for me to type when I was writing library functions.

Then, if I, personally, wanted to use "mz" for some quick hacking, I can easily make a macro that expands mz into ac-passthru [assertion untested]. Now I get to use "mz" when I want, but I'm not preventing other programmers from using "mz" for their code (an abbreviation for "moonlight zebras" in someone's code, perhaps? :)

-----

2 points by conanite 6207 days ago | link

Are you prematurely worrying about conflicting names ? :))

I admit I'm a bit confused about the bridging-code issue. I think if there was a bit of scheme functionality I wanted permanently available in my arc, I would add the relevant xdef in ac.scm. 'mz as it stands is fine for once-off or exploratory hacks, and as it's not there unless you've installed the patch, the name conflict isn't such an issue really.

I wonder is anyone preparing an app for mediocre zoos, motorcycle zen, or the Mark of Zorro?

-----

1 point by CatDancer 6207 days ago | link

Are you prematurely worrying about conflicting names ? :))

touché, mayhap I am

add the relevant xdef in ac.scm

Sure, that works. I prefer to program in Arc though.

as it's not there unless you've installed the patch, the name conflict isn't such an issue really

Oh, but I'm writing more code like my "lib" library which uses mz, so if you want to use my libraries, the name conflict issue will come up, if it is an issue.

Maybe I'll decide that I like "ac-passthru", not because I'm worried about possible future naming conflicts (which, as you point out, I've previously claimed should be dealt with in a different way), but because I think it's a better name for what it does.

An "mz" for once-off or exploratory hacks could after all be implemented in different ways, using ac-passthru or Scheme eval or connecting to a remote Scheme process, so I might be more comfortable not assuming that if I want to hack with a bit of Scheme code that passing through the Arc compiler is necessarily the way I want to do it.

-----

2 points by CatDancer 6208 days ago | link | parent | on: Lists as hash keys

obj quotes your key arguments for you (that's the job of obj), so what you want is:

  arc> (= foo (obj (int int) +))
  #hash(((int int . nil) . #<procedure:...t/git/arc/ac.scm:602:9>))
  arc> (foo '(int int))
  #<procedure:...t/git/arc/ac.scm:602:9>
Saying (obj '(int int) ...) will use (quote (int int)) as the key.

Also, there is a bug in arc2 with using lists as keys in a table, to be fixed in the next Arc release. (See http://arclanguage.org/item?id=9151)

-----


Hmm, in my application MzScheme is crashing with "Process scheme segmentation fault" when I use this.

-----


At this stage, MzScheme is reading lists from the input file as data. Once a complete list has been read, Arc then takes that list and interprets it as a piece of Arc code.

On line 4, the MzScheme reader sees the first opening parenthesis which starts the def. It then reads all the way to the end of the file without finding a closing parenthesis, and so complains that it isn't able to read the list starting on line 4.

-----

2 points by conanite 6210 days ago | link

ummm ... doh. I understand now, it's reporting the line number of the unmatched opening paren ... I was thinking it was the line number where the missing one should have been. thanks.

-----

3 points by CatDancer 6210 days ago | link

In the description I moved the comment up a line so it doesn't make it appear that the parser is doing magic ^__^

-----


  arc> (= parent* (obj thing* (obj this "that")))
  #hash((thing* . #hash((this . "that"))))
  arc> (fill-table (parent* thing*) (list 'more "that"))
  Error: "reference to undefined identifier: _thing*"
What do you want thing* to be? A symbol? A table?

-----

1 point by thaddeus 6211 days ago | link

I imagine a table as I would like to perform all the normal table operations on it like:

    (keys mything*) 
     
     or (mything* 'this)
     etc etc...
I initially thought a function like (point mything* (parent* thing*)) would be ideal, but then realized it would also probably require the 'let' usage to work otherwise the scope would be a problem.

T.

-----

1 point by CatDancer 6211 days ago | link

So table thing* is a key in the table parent*?

Could you either describe what you want to accomplish or else give some working code examples that you'd like to see simplified? I'm having trouble figuring out what you want your code to do from these fragments.

-----

1 point by thaddeus 6211 days ago | link

    -> So table thing* is a key in the table parent*?

    Yes.
Ok so this is probably exposing how newbish I really am, but please bear with me.... I tried to create an example that better describes what I am thinking.

Data set up:

    (= app* (table))
    (fill-table app* (list "yardwork" 
	                       (obj budget*   (table)
                                forecast* (table))))
    (fill-table app* (list "house" 
	                       (obj budget*  (table)
                                forecast* (table))))

    (fill-table ((app* "house") 'budget*) (list "roof" 1996.0))
    (fill-table ((app* "house") 'forecast*) (list "roof" 1996.0))
    (fill-table ((app* "house") 'budget*) (list "windows" 1000.00))
    (fill-table ((app* "house") 'forecast*) (list "windows" 1800.0))
so instead of doing this:

    (def area-situation (area sub-area)
         (let area-budget (((app* area) 'budget*) sub-area)
         (let area-forecast (((app* area) 'forecast*) sub-area)
         (let delta (- area-forecast area-budget)
         (if (is delta 0.0) 
               (let newval (list sub-area 200) 
                   (fill-table ((app* area) 'budget*) newval)))
         (prn (list "forecast " area-forecast " budget " (((app* area) 'budget*) sub-area))))))
    )

    arc> (area-situation "house" "roof")
    (forecast  1996.0  budget  1996.0)
I was thinking it would be nice to set up all my pointers at the beginning, then the last few lines of code ,where the meat is, become less cluttered with syntax and more about what, from a conceptual perspective, I am doing:

note: p = (point this (at that))

    (def area-situation (area sub-area)
         (p budget ((app* area) 'budget*)) 
         (p forecast ((app* area) 'forecast*))
         (p area-budget (budget sub-area))
         (p area-forecast (forecast sub-area))
         (= delta (- area-forecast area-budget))
         (if (is delta 0.0) 
              (let newval (list sub-area 200)
               (fill-table area-budget newval)))
         (prn (list "forecast " area-forecast " budget " area-budget))
    )

    arc> (area-situation "house" "roof")
    (forecast  1996.0  budget  200)
So you'll notice a few things; in function 1 - the last line requires having the full syntax for getting the roof budget; otherwise even though it's been re-set to 200; the let statement prior had already been set to 1996.0; so it forces me to re-use the syntax again; where ares the pointer notion in function 2 would not.....

Anyways - just the way my mind thinks (like a big spreadsheet haha). :)

T.

-----

2 points by CatDancer 6210 days ago | link

When you have two expressions that are similar,

  (((app* area) 'budget*) sub-area)

  (((app* area) 'forecast*) sub-area)
write a function consisting of the parts that are the same, and make the parts that are different into variables:

  (def (price area type subarea)
    (((app* area) type) subarea))

  (def area-situation (area sub-area)
    (let area-budget (price area 'budget* sub-area)
      (let area-forecast (price area 'forecast* sub-area)
         (let delta (- area-forecast area-budget)
I would continue iteratively with this process of turning similar expressions into functions, but it looks like you may have a bug in your code? You store a new budget but print out the old one. Unless that's what you wanted?

There are a couple of advantages to this process of noticing expressions in your code that are similar and turning them into functions. First, you don't have to figure everything out in advance. You write some code and get it to work right. Then you look for similar expressions and turn them into functions. In practice this works a lot better than trying to figure out what functions you're going to need ahead of time.

The second advantage is that it makes your code easier to change. For example, suppose you wanted to change your representation of your prices from tables inside of tables into lists, or perhaps one table with a compound key. If you have lots of places where you say (((app* area) type) subarea)) then you'd need to change all of those, but if you have a few functions like price then you only need to change those.

-----

1 point by thaddeus 6210 days ago | link

ugh, sorry.

The code didn't have the bug the results I gave did (too much copying and pasting) :)

the first function actually returns 200. (forecast 1996.0 budget 200)

what I had intended to convey was that I had believed I was required to use the full syntax (((app* area) 'budget*) sub-area) in order to get the 200, which I did, but I wanted to just use 'area-budget' to make it more readable.

But as I learned there were so many things I was doing wrong it wasn't funny ... even though I am laughing now. bewahahahah ! :)

Thanks for the reply. T.

-----

1 point by CatDancer 6211 days ago | link

I'll take a look at this, but it may be a couple days before I have a chance to get to it.

-----

1 point by thaddeus 6211 days ago | link

no worries, it's not a real problem I have to solve. I'm just trying to figure out what options/techniques are available.

Thanks. T.

-----

3 points by conanite 6211 days ago | link

app* is a nested structure something like this:

  app*
    yardwork
      budget
      forecast
    house
      budget
        roof = 1996.0
        windows = 1000.0
      forecast
        roof = 1996.0
        windows = 1800.0
And you want a clean way to access, for example, (((app* 'house) 'budget) 'roof), given 'house and 'roof as parameters.

Am I right so far?

An alternative definition of area-situation might look like this:

  (def area-situation (area sub-area)
    (with (budget   ((app* area) 'budget)
           forecast ((app* area) 'forecast))
      (if (is (- (budget sub-area) (forecast sub-area)) 0)
        (= (budget sub-area) 200))
      (prn "forecast " (forecast sub-area) " budget " (budget sub-area))))
You can use 'with to create variables pointing just to the two tables you need and then there's less digging to do when you need to look up or alter values.

You might get better mileage by changing the data structure though if that's possible:

  app*
    yardwork ...
    house
      roof
        budget = 1996.0
        forecast = 1996.0
      windows
        budget = 1000.0
        forecast = 1800.0
Then, area-situation becomes even simpler:

  (def area-situation (area sub-area)
    (let situation ((app* area) sub-area)
      (if (is (- (situation 'budget) (situation 'forecast)) 0)
        (= (situation 'budget) 200))
      (prn "forecast " (situation 'forecast) " budget " (situation 'budget))))
Arc doesn't really have "pointers" (at least not in the c/c++ sense) - you either have global variables, or local (lexically-scoped) variables. So you can create a local variable pointing to the innermost table using 'let or 'with. Oh, I said "pointing" - well, they're kinda pointers.

Does that point you in the right direction, or did I miss the point entirely?

btw with the hot new special-syntax you can write app.area.sub-area instead of ((app area) sub-area) - see http://arclanguage.org/item?id=9220

-----

1 point by thaddeus 6210 days ago | link

wow!

i didn't have an appreciation for the 'hot new special-syntax' until I compared my original hack against your last function with the infixing....

    (def area-situation (area sub-area)
        (let situation app*.area.sub-area
          (if (is (- situation.budget situation.forecast) 0.0)
            (= situation.budget 200)
          (prn "forecast " situation.forecast " budget " situation.budget))))
This is awesome!

T.

-----

1 point by thaddeus 6211 days ago | link

    *Am I right so far?*
yep.

I have to spend more time using 'with'; it's not a well well used tool in my tool shed as it should be.

and your last solution looks great to me.

thanks. T.

-----

2 points by fallintothis 6211 days ago | link

Accepting the hypothetical that there's not a clear-cut way to simplify the data structures (hey, it happens), I can't think of much to do. I know what it is you want to do, as the problem does crop up from time to time -- trying to make use of the expression instead of the value of an expression. An obvious way to solve this would be to introduce a macro, e.g.

  (= app* (table))
  
  (deftem cost-sheet  ;or whatever.  probably a bad name.
    budget   (table)
    forecast (table))
  
  (= (app* 'house) (inst 'cost-sheet 'budget   (obj roof 1996.0 windows 1000.0)
                                     'forecast (obj roof 1996.0 windows 1800.0)))
  
  (mac budget (area sub-area)
    `(((app* ,area) 'budget) ,sub-area))
  
  (def area-situation (area sub-area)
    (withs (area-budget   (((app* area) 'budget)   sub-area)
            area-forecast (((app* area) 'forecast) sub-area)
            delta         (- area-forecast area-budget))
      (when (is delta 0.0)
        (= (budget area sub-area) 200))
      (prn "forecast " area-forecast "budget " area-budget)))
But this isn't a very palatable solution -- you'd need to define macros for each field, and even then they're only shortcuts, really. It'd be easier if there were a shorter way to do nested indexing (which there will be, come arc3: http://arclanguage.org/item?id=9163).

Upon writing this and finding someone else replying, I notice that conanite's post http://arclanguage.org/item?id=9326 contains probably the best solutions, though.

-----

1 point by thaddeus 6211 days ago | link

I like the mac idea too. if the concepts like "budget" and "forecast" are the main data concepts of the program; then I can see being able to re-use the macro a lot. Also I have to read up on 'deftem' and 'inst'.

thanks, T.

-----

More