Arc Forumnew | comments | leaders | submit | almkglor's commentslogin
4 points by almkglor 6580 days ago | link | parent | on: New types in Arc?

What you could do is, you could create an "opaque" function which gives access to your theorem data. Then wrap that function in an 'annotate form.

  (def theorem (f)
    (if (check-that-f-is-valid-theorem f)
        (annotate 'theorem
          (fn (cmd)
            (case cmd
              get
                f
              something-else
                (do-something-on f))))
        (error "Not a valid theorem")))
For that matter, since Arc is around "exploratory programming", in principle Arc will not allow anything that limits what the user can do.

In practice, most users are too busy working on stuff to bother doing something as stupid as (annotate 'theorem something_which_is_not_a_theorem) anyway.

In short: don't worry, be happy ^^

-----

1 point by thefifthman 6580 days ago | link

lol Exploratory programming is fine, but I don't need to explore anymore what a theorem is :-)

> "Arc will not allow anything that limits what the user can do"

Obviously this is not true, as Arc limits me such that I cannot create a safe theorem type. What this means is that I cannot let the user directly interact with Arc when building an interactive theorem prover; I have to wrap some kind of protective layer around it, which would probably hinder lots of the exploring!

-----

1 point by almkglor 6580 days ago | link

> lol Exploratory programming is fine, but I don't need to explore anymore what a theorem is :-)

Which is an admitted problem in current Arc: it forces you to explore well-explored areas sometimes.

> I have to wrap some kind of protective layer around it, which would probably hinder lots of the exploring!

Standard answer: macros.

As for safety: Read: http://paulgraham.com/langdes.html point 3.

-----

3 points by almkglor 6581 days ago | link | parent | on: Hypothetical Web App: Image Gallery

> All images should be sized down to a particular maximum size, and flickr style thumbnails should be generated for the gallery view.

Arc has exactly 0 support for this. Maybe add this to TODO list of libraries for Arc?

> How do we tell if the file is not an image?

Check the binary file for each of the common formats?

> What do you do then?

If it's not an image, summarily delete it and tell the user that it didn't match one of the supported formats.

> What if the file is really big, and eats up our bandwidth / disk space?

Set a limit on HTTP PUT or POST. If it exceeds a certain size, complain to the user.

Note however that the Arc Server does not support PUT operations yet.

> Do we have any support for truly temporary files?

/tmp ?

> We wouldn't want one user's file to upload over another, when we're still trying to shrink and process it. How do we avoid orphaning images if users re-upload things?

Tough. Not sure what you exactly mean with this though.

> Should user icons be considered the same sort of thing as gallery images?

Not sure what you mean by this either. What do you mean by "user icons"?

> Should we store anything relating to the images in our database at all?

Database? What database?

LOL.

Arc has 0 database support for that matter.

-----

3 points by kens 6581 days ago | link

What support do you need for image processing beyond (system "ImageMagick ...")?

But seriously, if you're planning to implement an image processing library, take a look at the Common Lisp bindings to ImageMagick: http://common-lisp.net/project/cl-magick/

-----

3 points by almkglor 6581 days ago | link

> What support do you need for image processing beyond (system "ImageMagick ...")?

http://arclanguage.org/item?id=3522

-----

1 point by tiglionabbit 6581 days ago | link

>> We wouldn't want one user's file to upload over another, when we're still trying to shrink and process it. How do we avoid orphaning images if users re-upload things?

>Tough. Not sure what you exactly mean with this though.

This was actually part of the previous point, about temporary files. Many languages have tempfiles in their standard library. These help when you have a lot of users uploading things, and you want to make sure files don't clobber each other before you can decide where to put them. http://docs.python.org/lib/module-tempfile.html http://www.ruby-doc.org/core/classes/Tempfile.html

>> Should user icons be considered the same sort of thing as gallery images?

>Not sure what you mean by this either. What do you mean by "user icons"?

Most forums and art sites let their users upload a little picture, which is placed by each of their comments or posts. The difference between this and a normal image on the site is that, while other pictures may exist in different forms (e.g. full view / original, medium size, and thumbnail), user icons often only show up in one small standard size, and the original image they were shrunken from is not saved.

-----

1 point by sacado 6581 days ago | link

As for database, I think sqlite was almost working last time I looked at it. Maybe it's working now ?

-----

2 points by almkglor 6582 days ago | link | parent | on: arc2c update

Re: eval - We need a way to implement 'apply.

It's not easy. We can't make it into a primitive, because CPS conversion assumes that primitives will never need access to continuations, and thus does not transform primitive calls to CPS form.

-----

1 point by sacado 6581 days ago | link

Couldn't it be implemented as :

- PUSH the closure to be called

- PUSH the list of args

- call the APPLY() function, which just POPs the two elements, PUSHes all the elements of the arg list one after one, then call the closure (maybe after changing the continuation argument of that closure by hand, at runtime) ?

That's a runtime behavior, for sure, and probably a few cases should be hard-coded in the generated C file. E.g., (apply + '(1 2)) should be translated to (+ 1 2), then to 3, if nothing bad (redefinition of '+ or 'apply by the user) happened. But in the general case, you can't know.

Anyway, we will eventually have to implement an interpreter in the generated code, to deal with dynamic stuff. Maybe closures should be made available through a hashtable mapping their name(s) to actual code, and not only through a hard-coded array as it is now ?

-----

1 point by almkglor 6580 days ago | link

> Couldn't it be implemented as :

> - PUSH the closure to be called

> - PUSH the list of args

> - call the APPLY() function, which just POPs the two elements, PUSHes all the elements of the arg list one after one, then call the closure (maybe after changing the continuation argument of that closure by hand, at runtime) ?

Which continuation argument do you pass?

Suppose it's like this:

  (%car (%apply foo bar))
Then foo is:

  (set foo
    (fn (a b)
      (ccc
        (fn (k)
          (a k b)))))
Question: How does '%apply get access to the continuation, in order to pass to 'foo, which passes it to 'ccc ?

Remember, calling a function consists of the following steps:

1. Push the closure

2. Push the continuation

3. Push the arguments

The problem is step 2: continuation.

Possibly we need to insert the default 'apply during the same step as inserting the default 'ccc ? Then we could define '%apply as accepting the function, the continuation, and a plain list of arguments.

> Anyway, we will eventually have to implement an interpreter in the generated code, to deal with dynamic stuff. Maybe closures should be made available through a hashtable mapping their name(s) to actual code, and not only through a hard-coded array as it is now ?

s/closure/global variable/, maybe?

I think what we could do is, we add a pointer to an obj in the symbol structure. If the symbol is in the GLOBAL() array, this pointer points to that entry, otherwise to a malloc()'ed location.

-----

1 point by sacado 6581 days ago | link

oh, yes, 'apply & CPS... Well, I'll have a look at that today. I'll see if I can work around it.

-----

1 point by almkglor 6582 days ago | link | parent | on: Arc3.tar

LOL.

Hey! Hey! But Anarki is still being updated regularly! <watches in horror as nose grows>

-----

2 points by almkglor 6582 days ago | link | parent | on: Nondeterminism

In order to allow using amb in multiple threads (Anarki only!):

  (def getcc ()
    ccc.idfn)

  (= amb-stack* (thread-local))
  (= (amb-stack*) nil)

  (def fail ()
    (aif (amb-stack*) ((pop (amb-stack*)) nil) (err "no more choices left")))

  (mac amb vals
    ; use w/uniq !!
    (w/uniq return
      `(point ,return
        ,@(map
           [idfn `(aif (getcc) (do (push it (amb-stack*)) (,return ,_))) ] vals)
        (fail))))

-----

3 points by almkglor 6582 days ago | link | parent | on: arc2c update

Try this:

  (create-acct "frug" "yourpassword")
  (writefile1 'frug adminfile*)
  (asv)
Then go to http://127.0.0.1:8080/login and enter "frug" and "yourpassword". Then go to http://127.0.0.1:8080/repl

As for auto-update, well, none yet.

-----

1 point by TookTooMany 6581 days ago | link

Thanks!

-----

1 point by almkglor 6582 days ago | link | parent | on: arc2c update

None yet. What's currently blocking us badly is handling macros in the code for compilation. Like any decent Lisp program, arc2c makes quite a bit of use of macros.

Unfortunately macros require us to embed an Arc interpreter in the compiler itself, and we can't use the builtin 'eval because we don't want the macros under compilation to accidentally bash global functions/variables used by the compiler itself.

You'll have to contact sacado if you're interested in chipping in, we haven't figured out how to make a git on github publicly pushable.

-----

7 points by almkglor 6582 days ago | link | parent | on: Multiple Return Values?

The canonical Arc way of doing it is by returning a list. Then you can deconstruct it with 'let:

  (def sum-and-diff (a b)
    (list (+ a b) (- a b)))

  (let (sum diff) (sum-and-diff foo bar)
    (do-something-on sum)
    (do-another-thing-on diff))

-----

3 points by bOR_ 6582 days ago | link

I picked that habit up from some of the examples in the forum, and it works for me. Is there a reason why one would really want multiple return values?

  (= abba (list 1 12))

  (let (x _) abba
     (prn x))

-----

6 points by absz 6582 days ago | link

You can also use nil or t as your "ignored variable", instead of _; they won't even be rebound. E.g.

  (let (a nil nil d) (range 1 4)
    (list a d))
produces the list (1 4).

-----

3 points by eds 6582 days ago | link

The one nice thing about multiple values that I don't think returning lists accomplishes is that if you have a function that doesn't expect to receive multiple values, it will just use the first value returned. For example, in CL, #'truncate returns two values, the quotient and the remainder. But if you pass the return values of #'truncate to #'+, it just pretends you only passed a single value.

  * (truncate 5 3)
  1
  2
  * (+ (truncate 5 3) 6)
  7
I don't know of any way to make this work implicitly with returning lists... you would need to explicitly test if you were receiving a list and then destructure it accordingly. (Please correct me if you know of a better way around this.)

-----

5 points by almkglor 6582 days ago | link

Using (car:truncate ...) is th best I could think of ^^

-----

2 points by bOR_ 6580 days ago | link

that's pretty close to perfect.

Anyway, I suppose that the programmer knows what the output is of a certain function, and not be surprised if a function churns out a list rather than two values ;).

-----

3 points by bogomipz 6577 days ago | link

What if your function originally just returned one value, but at some later point you realize that a second value would be useful in some situations?

With multiple return values you can just extend it without breaking existing clients. If, on the other hand, you add a list wrapper around the returned values, all call sites must be changed to take car of the list.

-----

3 points by bOR_ 6571 days ago | link

That would be useful indeed. The flip side of the coin might be something that was sort of mentioned in 'on lisp'. If all functions return only one value (be it a list or a single value) by default, you can write a general memoize layer around functions that doesn't have to check how many multiple return values are returned.

I also noticed a carif function in arc. If you are worried about single values that will become lists in the future, you might start using carif in your current clients.

-----

2 points by dreish 6582 days ago | link

Returning multiple values puts multiple non-GC'd values on the stack. This is fast, but capturing and using those values is somewhat inconvenient for the programmer. Returning a cons creates one other cons in the heap that will need to be GC'd for each additional value returned.

-----

1 point by almkglor 6581 days ago | link

In theory we could do this with arc2c. However, I'm not 100% sure this is necessary with a "really good" optimizing compiler.

We could defer destructuring of arguments in arc2c to as late as possible, so that we could do some amount of optimizing away 'cons cells when the cells themselves are used only for returning multiple values. Which is arguably difficult, since each stage in arc2c expects arguments to be in undestructured form, i.e. (let (foo bar) niaw ...) => (let tmp niaw (with (foo (car tmp) bar (cadr tmp)))). If arguments are kept in non-destructured form, we would need to modify the way that function parameters are stored (to handle (o foo (expression))) and check each stage in the compiler.

Edit: When optimizing raymyers' treeparse, I actually transformed parsers to CPS form in order to return multiple values without all the construction and deconstruction of 'cons cells, which helped reduce some of the overhead.

-----

2 points by almkglor 6583 days ago | link | parent | on: arc telnet

In my experience peekc doesn't seem to work properly (i.e. as advertised) at all.

I assume you're doing peekc so that you can do something else while waiting for a character? If that is what you're trying to do, I suggest you use threads:

  (let ch nil
    (thread (= ch (readc:car inout)))
    (while (no ch)
      (do-something-while-waiting))
    (do-something-with ch))

-----

1 point by bOR_ 6577 days ago | link

(waiting for a program to calculate the variation in epitope clusters, so working on this for a moment)

  (= mudpipe (tcp-connect "avendar.com" 9999))

  (def readmud ()
     (let ch nil
       (thread (= ch (readc:car mudpipe)))
       (while (no ch)
       ; wait patiently
       )
     (pr ch)
     (readmud)))

  (= mudreader (new-thread readmud))

(first time I work with threads) readmud only reads one character at a time, and I want it to just keep on writing as long as there is data. I'll try to add a thread that calls readmud again the moment it returns something sensible.

Partial success. The reading bit seems to function fine (if slow ;), and I now can use arc while in the background the muds' output is being read, but still cannot write. Did add mzscheme's flush-out (but perhaps in some wrong way. Will look at it during the next work-break ;).

-----

1 point by almkglor 6576 days ago | link

Err. If you're just waiting patiently.... why not just readc directly?

  (def readmud ()
    (pr:readc:car mudpipe)
    (readmud))

-----

3 points by almkglor 6584 days ago | link | parent | on: sorting table keys

Err. How do you expect the keys to be sorted? Is #\p < (bite #\p) ? You have to specify your own sort function, replacing < with a (fn (a b) ...) specifying how you want it to be sorted.

-----

1 point by bOR_ 6584 days ago | link

That points me in the right direction at least. I'd have wanted that everything in the list is just seen as a string, so "#\p" would indeed be smaller than "(bite #\p)" if the character "#" has a lower ascii code than "(".

coerce looked promising, but i'm not sure how to force a list like (bite #\p) into the string "(bite #\p)".

  (#\T #\p (bite #\p) (bite #\f) (bite #\P) (bite #\R) (bite #\S) (bite #\T) #\f #\B (bite #\B) #\P #\R #\S)
  (map [coerce _ 'string ] (keys craa!eltm))

  arc> (map [coerce _ 'string ] (list #\T #\p #\f))
  ("T" "p" "f")

-----

1 point by absz 6584 days ago | link

The best way to do this is

  (sort (fn (a b)
          (< (tostring:write a)
             (tostring:write b)))
        (keys the-table))
; write will print the list, in that format, to stdout, and tostring captures stdout and puts it in a string, which it returns.

-----

1 point by bOR_ 6584 days ago | link

works like a charm. thanks!

-----

More