Arc Forumnew | comments | leaders | submit | almkglor's commentslogin

$ probably needs to demangle names by applying 'unpkg on them.

  <User>tl: 'x
  <User>x
  <User>tl: (using <arc>v3-packages)
  t
  <User>tl: (unpkg 'x)
  x
For that matter, while reviewing arc.arc, I noticed that there are quite a few file-related functions already exported from mzscheme into arc-space. I suspect bits of files.arc can be rewritten to use those functions instead.

Personally I think it's better to do something like this:

  ($.mzscheme-function param1 param2)
Then we can simply define $ as:

  (mac $ (x)
    `(seval ',(<arc>unpkg x)))
edit: pushed a version of files.arc on arc-f. To use, just (using <files>v1)

-----

1 point by stefano 6155 days ago | link

Thanks. I've made my own working version of files.arc when I discovered 'unpkg, but I couldn't push it because I didn't have access to internet :(

Basically I implemented a version of '$ that automatically unpackages symbols except those given in a list.

-----


Is this the classic PG ArcN from http://ycombinator.com/arc/arc2.tar ? I think it's a bug in that version only, which fails with symbol syntax.

-----

1 point by zhtw 6155 days ago | link

Yes. So now I really have to switch to your branch of Arc. (Just didn't want to do it while everything was working in originall Arc2.)

-----


Yes. I don't intend to have html.arc, user.arc and asv.arc to load on startup, instead, I expect the user to have to explicitly do:

  (using <asv>v1)
....which will load asv.arc, and asv.arc will then have dependencies on <html>v1 and <user>v1. If you have an app that needs <asv>v1, then put the (using <asv>v1) declaration in your app's source.

After all, not everyone will use Arc for web apps ^^

edit:

Also, as.scm attempts to precompile arc.arc into a scheme file. It loads those faster. I'm wondering if it would be possible to integrate the precompilation so that any 'using metacommand will precompile all libraries, just for the faster load times.

It would probably be better too to figure out what mzscheme's equivalent to fasl files is, and target that instead of just a .scm file.

-----


This is the Arc fork I've been ranting about recently.

More stuff and commentary later.

No arc http server yet, arc http server will need to be ported somewhat due to symbol-based packages.

Need more docs.

Bye have to go to work now.

-----

2 points by almkglor 6157 days ago | link

Okay, many of the main differences are described here: http://arclanguage.com/item?id=8266

I'll be adding more text documents soon

-----


I'm forking Arc with (among other things) a scanner concept.

Briefly, a "scanner" is any object that has methods defined for 'car and 'cdr (among other things, my Arc fork has/will have CLOS-style generic functions, but won't have inheritance; I'm trying to figure out whether I need inheritance at all in a duck-typed language, especially if I go the generics route for code reuse), and defines identity-function bindings for 'scanner and 'unscan.

'scanner usually throws an error (so that you can't map numbers, for example), but you can overload this for your type so that you return a valid scanner.

'unscan converts a scanner to the desired type.

Additionally, a user-defined type may overload two base functions, '<base>collect-on and '<base>each. Briefly, these functions construct a type iteratively ('<base>collect-on) and iterate over the type for as long as necessary ('<base>each - unlike 'each, this has an early out).

A type doesn't have to define '<base>collect-on and '<base>each, since they will work in terms of 'unscan (for '<base>collect-on) and in terms of 'scanner, 'car, and 'cdr (for '<base>each), but if your type doesn't look like a 'cons cell, it will probably be more efficient if you overload them for your type.

'each is defined in terms of '<base>each, and 'map (or more specifically, 'map1) is defined in terms of <base>collect-on and <base>each.

So yes: pretty much I'm just doing this from a different angle, i.e. typesystems and generic programming.

----- comments on your code:

  (let lazy-map map
    (= lazy-map
      (with-closure lazy-map 'cons lazy-cons)
       lazy-map
      (with-closure lazy-map 'map lazy-map)))
This is bugged ~.o . Wanna make a guess why? Hint: (= x (cons x 1) x (cons x 1)) is....

-----

2 points by rincewind 6159 days ago | link

Your generic programming solution is like the one from clojure. Clojure has a "conj" (pun on cons) function that adjoins a value to a collection, depending on the type of the collection. When you conj onto a vector you get a vector and when you conj onto a lazy list you get a lazy list.

My code may seem a bit buggy, but i thought of this example as a spec, so it cannot be wrong :)

-----

3 points by almkglor 6158 days ago | link

> My code may seem a bit buggy, but i thought of this example as a spec, so it cannot be wrong :)

1. If with-closure is a nondestructive operation (returns a copy of the original function plus modifications), then what gets returned is this:

  (= lazy-map1 map)
  (= lazy-map2 (with-closure lazy-map1 'cons lazy-cons))
  (= lazy-map3 (with-closure lazy-map2 'map lazy-map2))
  (= lazy-map lazy-map3)
2. If 'with-closure is a destructive operation (i.e. modifies the given function) then you've just clobbered 'map.

The proper solution would be:

  (= lazy-map nil)
  (= lazy-map-delay
     (fn rest
       (apply lazy-map rest)))
  (= lazy-map (with-closure (with-closure map 'cons lazy-cons) 'map lazy-map-delay))
In addition, 'lazy-cons will probably end up being a macro, because it fools around with execution; if you can arbitrarily replace a function with a macro (i.e. "true first-class macros"), that will require some serious metacompiling at runtime.

-----

1 point by rincewind 6158 days ago | link

You are right.

3. With-closure is a special form with call-by-name semantics for its third argument.

   (let lexical-var value
      (with-closure function 'name lexical-var)
      (= lexical-var anothervalue))
should only work with lexical-var as a lexical variable. When lexical-var is changed, 'name is also changed, like in normal closures. This could be implemeted by sharing structure of the closure-alist in ac.scm.

-----

1 point by almkglor 6158 days ago | link

> This could be implemeted by sharing structure of the closure-alist in ac.scm.

Um. There's no such thing.

The arc-on-mzscheme implementation uses mzscheme functions for its own functions. What I mean is, something like this:

  (fn (x) x)
is exactly the same as mzscheme's:

  (lambda (x) x)
This is still not trivially implementable in mzscheme except by some serious mangling around (i.e. basically each Arc function becomes an object with a "lock" function which assigns free variables to specific values. By default when we execute this function we specifically lock the free variables to the global variables).

And true first-class macros will still remain very difficult.

You might be interested in my discussions with shader about how true first-class macros make it very hard to write efficient interpreters, must less even lousy compilers. http://arclanguage.com/item?id=8015

It's possible, but very difficult, and in general most implementeers will not find it worth their while to implement first-class macros.

-----

1 point by applepie 6152 days ago | link

Should we really be so worried about efficiency?

Of course you are free to design and implement any language you want, and I know you've probably been the main contributor.

But I think the original spirit of Arc was to design a simpler language even if it couldn't be implemented as efficiently:

(Quoting pg, The Hundred-Year Language):

There's good waste, and bad waste. I'm interested in good waste-- the kind where, by spending more, we can get simpler designs. How will we take advantage of the opportunities to waste cycles that we'll get from new, faster hardware?

-----

2 points by almkglor 6152 days ago | link

Of course not. Conceptually, Arc-F is just as clean as Arc. You can implement CLOS-style monomethods in Arc-F from the Arc-F side. You can implement the '+, '-, '* and '/ operators on the Arc-F side (you just need to provide the basic '<base>+ etc. operators on the underlying base system side). And I'm willing to bet most of you would never have imagined that not all functions in Arc-F are functions (some of them are special objects that are interpreted by Scheme) if I never told you about that.

For example:

  <User>tl: +
  #<procedure>
  <User>tl: (list +)
  (#4(l-reductor #<procedure> #<procedure> #<procedure>))
Arc-F divides itself into the "IDEAL" and the "REAL". The "IDEAL" is how the language would be implemented in terms of the most basic axiomatic operators. "REAL" is how it has to be implemented to prevent it from being 10x slower than Anarki (yes, I actually did the IDEAL part first, and only later ported to the REAL part where bits of it are in scheme. We're talking 12 second load times for arc.arc, and arc.arc only).

Even PG himself abandoned the purely axiomatic approach when he found that performance was very, very bad. My aim is to return to a purely axiomatic approach in the IDEAL and to make appropriate hooks for the REAL part to optimize everything. As at is, Arc-F is about 2x-3x slower than Anarki. For me, that's acceptable. And so far, most of the speed loss is from function calls.

-----

1 point by almkglor 6152 days ago | link

As a concrete example: in Arc-F, it's possible to overload '+ by simply overloading <base>+. If you have a new type foo and want to define how to add two foos together, you just overload <base>+. The neat thing is that this won't slow down arithmetic very much, if at all; if you were to write the equivalent overload '+ in Anarki (Anarki doesn't have the <base>+ hook, after all), arithmetic performance suddenly drops precipitously.

Also, overloading <base>+ is simpler: <base>+ only requires that you consider the case of adding two objects. + determines how to handle things when you do (+ foo1 foo2 foo3 foo4), specifically it converts the call to (<base>+ (<base>+ (<base>+ foo1 foo2) foo3) foo4)

So yes: my position is, by focusing on efficiency in implementation, it frees us to actually use the axiomatic approach without throwing in the towel and going non-axiomatic.

-----

2 points by stefano 6151 days ago | link

I like the REAL/IDEAL distinction. Always following the IDEAL path to make the "one hundred year language" without considering performance easily leads to unacceptable performance. Your experience with 'load clearly shows that.

-----

1 point by rincewind 6158 days ago | link

I see it now. The env parameter in ac is the lexical environment at function definition time.

-----

1 point by almkglor 6160 days ago | link | parent | on: Packaging libraries

'int->str is buggy:

  arc> (int->str 1 10)
  "00000000001"
  arc> (int->str 10 10)
  "00000000010"
  arc> (int->str 11 10)
  "00000000011"
  arc> (int->str 100 10)
  "100"

-----

1 point by stefano 6160 days ago | link

It's a problem with the math. I use (quotient n 10) where I should use (+ 1 (coerce (log 10 n) 'int)), where 10 is the base of the logarithm. I'll have also to add 'log to ac.scm, because it's not there...

-----

2 points by almkglor 6159 days ago | link

Actually you could have used this arc.arc function:

  (def pad (val digits (o char #\ ))
    (= val (string val))
    (string (n-of (- digits (len val)) char) val))

Obviously arc.arc itself needs some serious documentation T.T

-----

2 points by stefano 6159 days ago | link

> Obviously arc.arc itself needs some serious documentation

I completely agree. It's not the first time I write a function and then discover that it is already there. I could just read all the Arc source code and try to remember everything, but I don't have enough time. What about a book on Arc written by the community?

-----

3 points by stefano 6159 days ago | link

Created: http://github.com/stefano/arc-book/tree/master

I'll give write access to anyone who wants to contribute with some piece of documentation.

-----

2 points by skenney26 6158 days ago | link

I'd be interested in contributing. Perhaps we should discuss possible topics for the first few chapters.

-----

2 points by stefano 6158 days ago | link

I've just added you as a contributor, you should now be able to push things. The book should look as a natural continuation of the Arc tutorial. The book should target Anarki, not Arc2. A nice first chapter would be an overview of the most basic Arc macros and functions together with some examples. A chapter on system administration scripts with Arc could also be a good introductory chapter. I would leave web application development as one the last chapters. A chapter on the available third-party libraries could be a good one.

-----

1 point by almkglor 6155 days ago | link

Would you be interested in having an "Arc-F" section?

I wrote what was supposed to be a rationale for the scanner abstraction, but it ended up looking more like a tutorial, LOL.

-----

1 point by stefano 6155 days ago | link

I was in fact thinking about a small section on arc-f installation (when I find the time) :). I'll give you access to the repository as soon as possible, I have to run now.

-----

1 point by stefano 6155 days ago | link

Ok, now you have read/write access to the repository: http://github.com/stefano/arc-book/tree/master

-----

1 point by almkglor 6151 days ago | link

@stefano:

Do you mind if I put a simplified BSD license on the Arc-F section of the arc-book?

Do you have any preferences for licensing?

-----

2 points by stefano 6149 days ago | link

The more permissive the license, the better. BSD should be fine.

-----

1 point by rincewind 6159 days ago | link

What do you have in mind?

"The Arc Cookbook", "Practical Arc"?

TeX, HTML, Markdown?

-----

2 points by stefano 6159 days ago | link

I don't have anything particular in mind. Everything that classifies as "documentation" is good.

> TeX, HTML, Markdown?

I think TeX would be a good choice.

-----

2 points by almkglor 6158 days ago | link

> I could just read all the Arc source code and try to remember everything, but I don't have enough time.

This is what I do every week.

LOL.

I need a girlfriend wahahahahahaha

As an aside, I've been forking Arc to include the symbol-based packages, and the 'interface thing is a rather nice documentation in and of itself: it's kinda like a summary of the functions available, sort of like a "table of contents".

-----

2 points by stefano 6158 days ago | link

I'm looking forward to see your fork released! Have you introduced any relevant incompatibility with Anarki?

-----

5 points by almkglor 6158 days ago | link

Yes, off the top of my head: 'each on tables gives you the cons pair (k . v), instead of just values. passing strings to 'map for third->inf arguments no longer infects the output type; rather, the output type is always the type of the second argument.

t and nil are now boolean types, not symbols. Sorry. It's hard to reason about them with the newfangled type-based methods if they're symbol types instead of booleans.

Also, because of contexting, asv.arc will have to be rewritten so that it unpackages symbols in (defop ...) and related forms. If it's not rewritten, you'll have to use example.com/%3CUser%3Cyour-page instead of example.com/your-page . I think most asv-based applications will work properly if asv.arc is modded thus.

Also, most of your source files will probably need something like:

  (in-package my-file)
  (using <arc>v3)
You can leave that out but that means you'd be putting stuff in the <User> package, which is supposedly for exploratory scratch purposes (if your source is scratch, well then leave it out by all means ^^).

Note that <arc>v3 does not even include all arc functions (for example <arc>v3-thread, which includes the threading stuff). There are some rationales for not including everything in <arc>v3, most notably for bits and pieces that are reasonably hard for other implementations, such as threads.

Also, the fork is somewhat slower, especially for function calls T.T . So far I haven't experienced particularly serious slowdowns (due to some serious crazy optimizations in ac.scm that were mostly inspired by my experimentations with implementing the SNAP interpreter).

However the fork does have nice advantages. For example, it has generic functions with methods. So far it's just the ordinary dispatch-on-first-argument-type but I hope to expand that in the future to create full-blown generic functions with dispatch-on-any-combination-of-argument-type.

Also, it's now much easier to integrate your own types into the base arc.arc . For example you can create your own sequence types which will work with 'map, 'join etc. Those functions will even return your type, i.e. map on your type will return the same type. Generic programming FTW!

And of course, packages, whose integration was the biggest headache in the fork T.T . Largely because I decided that everything that gets passed to the compiler should already be in packages; this includes fn -> <axiom>fn etc.

It can be launched from any directory, and will remain in that directory when you program, unlike Anarki which always cd's to the installation directory (but it will auto-search the installation directory for any 'load calls you make)

Slated for future is also a way to define ssyntax that works only within the scope of a package, meaning using your own ssyntax in one package won't affect another package.

-----

2 points by stefano 6157 days ago | link

I thought it was just about packages, but it is a much larger change! Well done! We really needed something new. I'll now look into integrating pack.arc with your package system.

-----

1 point by almkglor 6156 days ago | link

Thanks. You may wish to look through lines 381-383ish on ac.scm, which is the bit which calls 'require when you're trying to (using ...) some package.

I think pack.arc is nice enough to integrate into ac.scm and arc.arc (at the very least the package loading part; you can probably still retain the bit that creates packages into pack.arc, since it'll probably be used rarely enough)

Also, it might make sense to use the same context object for each file in a pack.

-----

1 point by stefano 6156 days ago | link

> you can probably still retain the bit that creates packages into pack.arc

Yes. I've written that part (defproject and related functions) as a base for a not-yet-written Arc IDE.

-----

1 point by bOR_ 6157 days ago | link

  "t and nil are now boolean types, not symbols. Sorry. It's hard to reason about them with the newfangled type-based methods if they're symbol types instead of booleans."
It's a bit hard for me to understand the consequences of this, and as you seem to be sorry about the change, I assume there are some consequences worth noting. Could you elaborate?

-----

1 point by almkglor 6157 days ago | link

It has to do with overloading 'car and 'cdr.

'car and 'cdr are now overloadable - see for example lazy-scanner.arc in arc-f/lib .

However classically (car nil) => nil and (cdr nil) => nil.

So basically we have something like this:

  (def car (x)
    (err "can't apply 'car to object" x))

  (defm car ((t x cons))
    ...some scheme-side code....)

  (defm car ((t x bool))
    (if x
        (err "attempt to scan t")
        nil))
Of course we could probably still retain t and nil as symbols. However the user might want to define iterating over symbols for some arcane purpose (exploratory, exploratory...). If 'nil is a symbol, the user has to specifically check for the nil symbol when overloading 'car for symbols.

The reason I'm sorry is really because I'm not 100% sure it's the Right Thing (TM), and because I really had to go on with Arc-F instead of dithering over 'nil.

-----

1 point by cchooper 6157 days ago | link

Of course, you still have the problem that nil is both a boolean and list :)

-----

2 points by almkglor 6156 days ago | link

Ah ah ah.... no! The cute thing is that a 'bool presents the "scanner abstraction". Basically, a scanner is anything that overloads the functions 'car, 'cdr, 'scanner, and 'unscan. Thus, you don't have to check for the type of an object: you just need to pass it through 'scanner. If 'scanner throws, it's not a "list". If 'scanner returns a value, you can be sure that it returns a value that will be legitimately passed to 'car and 'cdr.

From this point of view, a "list" is anything that happens to be a scanner.

So nil is a list. So are 'cons cells. So are anything that overloads 'scanner, 'unscan, 'car, and 'cdr.

Try:

  (using <lazy-scanner>v1)
...then play around with (lazy-scanner a d)

Or for a bit of ease of use generate an infinite list of positive integers (after doing the 'using thing):

  (generate [+ _ 1] 1)
Edit: to summarize: a list is not a cons cell. A cons cell is a list. ^^

-----

1 point by cchooper 6156 days ago | link

Ah...but...what if you want to define a generic function that operates differently on lists and bools (i.e. not a scanner, but a general generic function). I haven't had a close look at Arc-3F yet, so maybe I need to play around a bit more to uderstand what you're saying :)

-----

1 point by almkglor 6156 days ago | link

Well, a "list" is a "scanner". So your "not a scanner" doesn't make sense, at least from the point of view of Arc-F.

However if you mean "list" as in sequence of cons cells:

  (def works-on-cons-cells-and-bools (x)
    (err "this works only on cons cells and bools!"))
  (defm works-on-cons-cells-and-bools ((t x cons))
    (work-on-cons-cells x))
  (defm works-on-cons-cells-and-bools ((t x bool))
    (work-on-bool x))
Note that you can even define a unifying "type class" function which ensures that the given data is a cons cell or a bool, or is convertible to one (i.e. an analog to 'scanner). For example, you might want a "hooper" type class:

  (def hooper (x)
    (err "Not convertible to a bool or cons cell" x))
  (defm hooper ((t x cons))
    x)
  (defm hooper ((t x bool))
    x)
Then you can convert works-on-cons-cells-and-bools with the type class:

  (def work-on-hooper (x)
    (works-on-cons-cells-and-bools (hooper x)))
Then, someone can make a type which supports the "hooper" type class by either overloading hooper (and returning a true hooper), or overloading hooper and works-on-cons-cells-and-bools:

choice one:

  (defm hooper ((t x my-type))
    (convert-my-type-to-cons x))
choice two:

  (defm hooper ((t x my-type))
    x)
  (defm works-on-cons-cells-and-bools ((t x my-type))
    (work-on-my-type x))

-----

1 point by bOR_ 6156 days ago | link

in reply to the summary: nice.. some day I'll have to look into the bellow of the beast. Arc3F no longer has lists build up from cons?, or lists are build from cons which are a special kind of lists.

-----

2 points by almkglor 6156 days ago | link

Well, I prefer to think of cons-as-lists as one implementation of lists. It's possible to define alternative implementations of lists; all that is necessary is to define the overloads for 'car, 'cdr, 'scanner, and 'unscan. With generic functions in Arc-F, that is enough to iterate, cut, search, filter, join, map, and more on any list, regardless of whether it's made of 'cons cells or 'lazy-scanner objects.

-----

2 points by drcode 6158 days ago | link

arcfn.org is a good stopgap

http://arcfn.com/doc/fnindex.html

-----

1 point by almkglor 6158 days ago | link

True; high quality documentation, too.

It's not being updated, but then. neither is Arc ^^

-----

1 point by stefano 6160 days ago | link

Fixed.

-----

3 points by almkglor 6161 days ago | link | parent | on: Macro question

The Arc2 quasiquote fails if any sublist is improper, i.e. a dotted list.

-----

1 point by projectileboy 6161 days ago | link

Thanks to you and to cchooper for the help. I hadn't thought to run against Anarki.

-----

1 point by almkglor 6162 days ago | link | parent | on: Looking for advice

How long would 'pack-build-cache have to run? Is it possible for it to just check for newer packages? Because if it's not too long, it might be useful to have it start automatically, or even as a:

  (thread
    (while t
      (pack-build-cache)
      (sleep 1000)))

-----

1 point by stefano 6161 days ago | link

It just dumps the title and the description to a text file and there is no way to check only for newer packages. Maybe it would be possible with a real implementation, this is just a prototype. Making it run continously in the background is thus unacceptable. I don't think it's a problem for the user to type (pack-build-cache) after installing new libraries.

-----

5 points by almkglor 6162 days ago | link | parent | on: Jordan shoes

Presumably flagging requires PG to actually do something.

LOL.

I'm feeling snarky today ^^

-----

3 points by almkglor 6162 days ago | link | parent | on: Interesting macro 'focus

Similar to the 'breakable modifier:

  (breakable:map
    [when odd._
          (break _)]
    *list-of-numbers*)
Note however that the 'break function created by 'breakable is an early-out, i.e. it exits the 'breakable form.

I suggest you turn 'focus into say 'focusable so that the extra variable ref can be dropped and we can abuse the : syntax:

  (focusable:map
    [and odd._
         (or (no (focus))
              (< (focus) _))
         (focus _)]
    *list-of-numbers*)

-----

More