Arc Forumnew | comments | leaders | submit | akkartik's commentslogin
1 point by akkartik 4828 days ago | link | parent | on: Macros can now be declared out of order

Huh. Somehow that rep trick never occurred to me either.

One of my big motivations for first-class macros was to be able to organize my code in any order. If there's no external constraints it increases the odds that a given snapshot will have some reasonable organization that's easy for newcomers to understand. Any constraints just increase the odds of stale organization. I've ranted before about this: http://arclanguage.org/item?id=15587 (footnote 1); https://github.com/akkartik/wart/blob/master/001organization. If macros can be written in any order, that reduces a lot of my need for first-class macros.

-----

2 points by rocketnia 4828 days ago | link

Sorry to say, but I don't believe any of this actually lets you use macros before they're defined. Calling the macro's rep will just succeed at expanding the macro, not executing the resulting code (and not suppressing expansion and execution of the arguments).

-----

1 point by akkartik 4829 days ago | link | parent | on: State of the arc

Welcome back, shader!

Analogously to Pauan, I'd love to have you try wart. It's much slower and has fewer libraries than arc. But on the other hand it's cleaner, and has fexprs, python-like indent-sensitivity and python-like keyword args. At the very least, maybe worth a few minutes play? (And tell me what you think? :) Somebody using it may well be the impetus I need to go back to work on speeding it up.

http://github.com/akkartik/wart#readme

  $ git clone http://github.com/akkartik/wart.git
  $ cd wart
  $ ./wart
(Requires linux, gcc.)

Other than that, any contributions to anarki are also most welcome. Can you share what project you're planning?

-----

2 points by shader 4828 days ago | link

Hello akkartik, I'm glad to be back. I've been lurking on and off for the past few years, but it will be nice to get involved again.

I guess I should be fair and try yours out too while I'm at it, though I have to say that the whitespace sensitivity makes me somewhat cautious. For some reason, I've always liked the more traditional sexpr syntax for lisp. Does wart mind if I use parens for everything?

Even more disconcerting would probably be your infix support. Maybe it won't be as much of a problem as I'm expecting, but I like being able to use random symbols in my variable names.

Also, numbered git commits strikes me as a little odd, as does the numbered source files. In the latter case its little more than taste, and I see that Pauan is doing the same thing. Maybe you have a good reason for it and I'd start doing the same if I only understood.

Anyway, enough casting of doubt on someone else's pet project. I'm certainly interested in a clean language with the possibility of fexprs to try out and maybe even keyword args. I'm not sure what I would actually need them for, but more power is never something I will turn down.

I'm also somewhat interested in the wat/taf projects, but they seem to be a bit more experimental right now.

--

As for my project plans, I'm thinking of doing two or three web service projects on the side, as a long term investment counter-point to my current hourly contracting job.

The first one I'm thinking of focusing on is a sort of easy, data-driven unit-testing-as-a-service concept. If you've ever seen the fit or fitnesse testing frameworks, this idea was originally based off of those. Instead of writing unit test code, you would use a website to input test values and corresponding expected results in a table format. The first row of the table specifies the function or object being tested and its arguments or property names, and each row after would give the values for that test case, with the last column or set of columns specifying the return value. Fitnesse did that for c# and java, but it had a few major flaws. In the first case, it would only interact with classes that inherited from the fitnesse test classes, so you were forced to write test harness code anyway. Second, the user had to format the tables manually using a wiki format, so it required a bit too much manual formatting and there wasn't any way to provide additional metadata or add any more dimensions to the tables.

The first few incarnations would probably be something really simple that would only be useful for testing code locally, but eventually it would be expanded to a web service that supports multiple languages and has a way to point it at any vcs repo and run tests interactively in the cloud. This would hopefully be a cheapish testing and specification solution for startups or foss projects that would be easy enough to add to existing code that people would actually do it. That and an enterprise version that can be deployed internally, which would hopefully make it so that business analysts and the QA team can write, run, and review the tests without having the dev team write a separate test harness for them.

There's a bit more to the idea, but right now none of it has been written, so I probably shouldn't advertise features that I may never get to, or might not even be feasible in the first place. Of course, I like talking even more than I like coding, so I'm sure we can discuss it if you're interested. In fact, I would be very open to discussion, as I'm sure what other people actually want/need/would be willing to pay for in a test system won't match up exactly my own ideas.

-----

2 points by Pauan 4828 days ago | link

"In the latter case its little more than taste, and I see that Pauan is doing the same thing."

The reason I numbered them was just to make it easier to navigate the code. As a user, if you see "01 nu.rkt" you know it's loaded first, and that "02 arc.arc" is loaded second. And each one builds on the stuff defined previously, so you can read it in a linear order.

I only did that for the stuff that's automatically loaded when you start up Arc. You'll notice that the "lib" and "app" stuff is un-numbered. And I don't expect user-created code or libraries to use numbers! So I definitely don't take it as far as wart does.

-----

1 point by akkartik 4828 days ago | link

Ah, I was unaware of fitnesse! Thanks for the pointer, that's a really neat idea. Tests are a huge part of wart's goal of 'empowering outsiders'[1].

Sucks that fitnesse is stuck in the java eco-system. Just porting it to lisp/arc/wart would be awesome for starters..

Arguably much of the benefit of testing comes from the same person doing both programming and testing. Organizations which separate those two functions tend to gradually suck. If you accept that, inserting a web interface between oneself and one's tests seems like a bad idea. Perhaps fitnesse-like flows would be best utilized to involve the non-programmer in integration testing, testing the entire site as a whole rather than individual functions. Perhaps script interactions with a (non-ajax for starters!) app so that the CEO/QA engineer doesn't have to know about REST and PUT/GET? Hmm, that would be cool..

Don't mind me, I'm just thinking aloud :)

[1] https://github.com/akkartik/wart/blob/531622db6a/000preface. I spend a lot of time thinking about this, and at half an opening will fill your ears about all the ways in which tests, whilst awesome, aren't sufficient. Along with ideas for complementary mechanisms.

-----

3 points by shader 4828 days ago | link

Organizations which separate those two functions tend to gradually suck

Hmm... Well, that's certainly a valid opinion, and it may even be true in a lot of cases, however I think the issue is largely due to two other related issues: 1) The requirements aren't specified clearly enough, and are dissociated from the tests as well, and 2) they just don't have good enough tools.

Tests can serve many purposes. The most basic, given the fundamental concept of a test, is to tell you when something works, or when it doesn't. TDD focuses on the former, unit testing and regression testing focus more on the later. Tests can be used at different points in the development cycle, and if you use the wrong kind at the wrong point, it's not really all that helpful.

My concern is that its too difficult to write the correct kind of test, so most developers use the wrong kind or don't use any at all. There's nothing really wrong with that, I think it's just an unfortunate inefficiency, like trying to debug without stacktraces. >.> Hmm. Something to look forward to going back to arc I suppose. Anyway, my goal is to make testing easy enough to do, either for developers who just want a quick way to check if they broke something after making a 'minor' change, or for larger companies that want to know that all their requirements have actually been met.

So, to solve the first problem I'm hoping to utilize a lot of reflection and code inspection so that at least the outline of the test cases can be generated automatically, if not more. Then it should be really easy for the programmer to just add the missing details, either as specific test vectors or by using a more general definition of requirements using something like QuickCheck's generators.

In the long run the plan is for the tool to be able to support working the other direction, from requirements to tests. Hopefully with better tool support, and more intelligent interaction with the system under test, it should be possible for the architects to specify the requirements, and the tool should be able to verify that the code works.

Yes, divorcing tests from code could mean that different people do them. Doesn't have to be the case, but it becomes a possibility. And that means that they could will have a different perspective on the operation of the system, but not necessarily a worse one. If it's the architects or BAs writing the tests, then they might actually have more information about how the system should be working than the programmers, especially in the case that the programmers are outsourced. At which point allowing someone else to write the tests is an improvement. When developers write the tests, it doesn't help if they use the same incorrect understanding of the requirements for both the tests and the code.

Hopefully by making an easy enough tool that supports rapidly filling in tests based on code analysis (which would help anyone that doesn't know much about the actual code base match it up with the requirements they have) reducing boiler plate and barriers to testing, making it a much easier to use tool for developing. Maybe if it gets easy enough, developers would find that testing actually saves enough time testing to be worth the few seconds specifying test vectors for each method. And if it can do a good enough job at turning requirements into tests in a way that is clear enough to double as documentation, it should save the architects and BAs enough time, as well as make implementation easier for developers, that I might actually be able to sell licenses :P

-----

2 points by akkartik 4828 days ago | link

"If it's the architects or BAs writing the tests, then they might actually have _more_ information about how the system should be working than the programmers,"

Oh, absolutely. I didn't mean to sound anti-non-programmer.

I tend to distrust labels like 'architect' and 'programmer'. Really there's only two kinds of people who can work on something: those who are paid to work on it, and those who have some other (usually richer and more nuanced) motivation to do so. When I said, "Organizations which separate those two functions tend to gradually suck", I was implicitly assuming both sides were paid employees.

If non-employees (I'll call them, oh I don't know, owners) contribute towards building a program the result is always superior. Regardless of how they contribute. They're just more engaged, more aware of details, faster to react to changes in requirements (which always change). Your idea sounds awesome because it helps them be more engaged.

But when it's all paid employees and you separate them into testers and devs, then a peculiar phenomenon occurs. The engineers throw half-baked crap over to testers because, well, it's not their job to test. And test engineers throw releases back at the first sign of problems because, well, it's not their job to actually do anything constructive. A lot of shuffling back and forth happens, and both velocity and safety suffer, because nobody cares about the big picture of the product anymore.

(Agh, this is not very clear. I spend a lot of time thinking about large organizations. Another analogous example involves the patent office: http://akkartik.name/blog/2010-12-19-18-19-59-soc. Perhaps that'll help triangulate on where I'm coming from.)

(BTW, I've always wondered: what's that cryptic string in your profile?)

-----

2 points by akkartik 4828 days ago | link

"Does wart mind if I use parens for everything?"

Nope, that will always work as expected: https://github.com/akkartik/wart/blob/531622db6a/004optional.... I threw it out there since you mentioned python :) but syntax is the least important experiment in wart.

Re numbered files: they keep me from ever needing to refer to filenames in code: https://github.com/akkartik/wart/blob/531622db6a/001organiza...

Don't feel like you have to be fair :) The world isn't fair, and I understand about differences in taste. My goal with wart and some other stuff has been to figure out how to empower outsiders to bend a codebase to their will and taste with a minimum of effort. For example, one experiment I'd love to perform on you is to measure how long it takes you to fork wart to toss out infix and get back your beloved hyphens :) But no pressure.

-----


A paper on this in PLDI this year: https://code.google.com/p/virgil/downloads/detail?name=virgi...

-----

2 points by akkartik 4834 days ago | link | parent | on: Best way to deploy arc code

Yeah I've been using git with this workflow: http://joemaller.com/990/a-web-focused-git-workflow

-----

1 point by idoh 4834 days ago | link

Thanks Kartik. My git knowledge is about the level where I can pull and push to github and resolve minor conflicts, so this is probably a really basic question -

I know how to install git, but how hard is it to set up a git server to receive the remote pushes from dev?

-----

1 point by akkartik 4834 days ago | link

It sounds like you have ssh access to your server, in which case it's super easy, no server needed at all, git push will work over ssh.

-----

1 point by akkartik 4835 days ago | link | parent | on: Wart update: swapped are args to 'isa'

I have no idea what I was saying there, but it took me a couple of years to truly appreciate both your points :)

-----

2 points by rocketnia 4835 days ago | link

"I have no idea what I was saying there"

Oh, well I got a lot from it. :) I may have quoted you out of context just now, but I think your post was the first time I thought about the idea that optional args and Haskell-like currying may encourage opposite argument orders. If a function argument is going to remain mostly constant, it should go last so it can be optional, but it should also go first so we can curry it away.

Since then, I've come to think the conundrum is largely internal to currying itself: Currying is useful when people have a frequent need to insert their own locally constant value. That's a tenuous balance in itself, and only one half of it conflicts with the general idea of putting stable values toward the end.

(Here's another really old exchange about argument order in Haskell: http://arclanguage.org/item?id=4705)

At the moment, I just say no to currying. I even manually eta-expand higher-order applications so it's easier to see what function signatures I expect, and so they're easier to step through in a debugger.

  // No:
  _.arrAll( arr, _.isString )
  
  // Yes:
  _.arrAll( arr, function ( x, i ) {  // or just ( x )
      return _.isString( x );
  } )

-----

2 points by akkartik 4833 days ago | link

After reading http://arclanguage.org/item?id=4703, I wanted to be able to say both:

  (map f (keep f (sort > ..)))
and:

  (map :over seqs
       (fn (f) ..))
But I can't do that. The ways that wart gets in the way are instructive:

a) First I tried adding an alias to https://github.com/akkartik/wart/blob/2fa2a3b1c0/043list.war...:

  def (map f seq|over)
    ..
But it was easy to forget that I extend map later on: https://github.com/akkartik/wart/blob/2fa2a3b1c0/050list2.wa....

Lesson: when adding param aliases we need to update all later extensions. That seems painful.

b) Even after I identified both places to modify, it's unclear how to deal with this declaration:

  def (map f ... seqs)
I could make it:

  def (map f ... seqs|over)
But then this call combines all args into seqs.

  map :over fs
      (fn (f) ..)
Lesson: rest args by keyword sometimes don't work well. Better to try to find the right names for other args.

Maybe something like this?

  map fs :do (fn (f) ..)
I still can't think of the right keyword to make this readable.

Update: I ended up going with

  map fs :with (fn (f) ..)
(https://github.com/akkartik/wart/commit/537fb6d832)

I also made a change to permit keyword args after rest keyword args:

  map :over fs :with (fn (f) ..)
(https://github.com/akkartik/wart/commit/b3667cda49)

Which of these do people prefer? Any other options?

-----

1 point by akkartik 4835 days ago | link

Looking elsewhere in that thread, one idea for really-as is explicit currying:

  (as.int.nil.0 (arg req "id"))
..or something.

Hmm, at the very least, perhaps we can curry as so that we no longer need functions like int (though I know you prefer recognizers to types ^_^)

  (as.int "34")
Now wart's uniform left-associative precedence truly comes into its own:

  (as.int+arg req 'id)

-----

2 points by rocketnia 4835 days ago | link

"Hmm, at the very least, perhaps ... (as.int "34")"

I had thought about that for Penknife (http://www.arclanguage.org/item?id=13715). I was going to call it "ify" and then use it with the reverse application syntax:

  [int'ify:arg req s.id]
(Note Penknife's uniform left-associative precedence.)

Similarly, 'isa was going to be "ish":

  int'ish.x
However, I still don't see any semantic benefit in associating a coercion function with a type tag. This would have been nothing but a way to shove a bunch of different utilities into one organizational unit, like Java's static methods. And an organization style like this can backfire: If the system is trying to be securable according to the principles of object-capability model, a programmer who passes a whole open-ended bundle of utilities into untrusted code might accidentally expose more privileges than they've bargained for.

---

"though I know you prefer recognizers to types"

I was thinking of bringing that up in response to the OP, but I think I'm mostly on the side of type tags now! I use tables with "type" fields all the time. I like the ability to dump these tables at a REPL, serialize them, use 'iso for deep comparison, or pass them between frames (in JavaScript). This could be a mess if I use more of these features than I plan to support, but "adding" support is as easy as changing my mind. :-p

My old argument for maintaining a dedicated (foo? x) procedure was so that the 'foo? symbol could be namespaced just like any other member of the global scope. But if the type needs to go outside the language runtime and into serialized data or other concurrently executing runtimes (namely, browser frames), then runtime-local tools for namespace management aren't much help.

Fully abstraction-leak-proof namespace management amounts to having a secure notion of which programs have privilege over which namespaces. Cryptography makes it possible to achieve a pragmatic degree of security at the level of serialized data. I've been keeping this in mind as a guideline during my recent module system pursuit.

-----

2 points by akkartik 4839 days ago | link | parent | on: Wrong comments time

Ah, thanks for the report! That was my fault. This bug has been in anarki for over a year, ever since I messed with its templates: http://arclanguage.org/item?id=15664. In particular this highlights an issue with change a) at http://arclanguage.org/item?id=15690: when the default value is an expression like (seconds) for the time field, it's pointless not to inline it.

Stay tuned; I'll fix this in an hour or three.

-----

2 points by akkartik 4836 days ago | link

This is now fixed (as of https://github.com/nex3/arc/tree/3d643ea924). I ended up backing off on changing defaults; arc now goes back to providing no support for them whatsoever. It's too hard to track default values while we wrap exprs in functions.

It's also been a constant enough question in my mind how the current semantics differ from arc3.1 that I wrote up a report.

Arc3.1: https://github.com/nex3/arc/blob/3d643ea924/lib/tem-report.a...

Current: https://github.com/nex3/arc/blob/3d643ea924/lib/tem-report.c...

-----

2 points by Fenng 4839 days ago | link

Waiting for you ...

:)

-----

1 point by akkartik 4838 days ago | link

Ok, there's now a temporary workaround up: https://github.com/nex3/arc/commit/4492309637. Do a git pull.

This is harder than I thought. Things will likely change as I continue to work on this, so that templates written to disk now might not be quite what you get back after a git pull in future. If you put your email in the about section of your profile I'll notify you when that happens, and exactly what changed.

-----

2 points by Fenng 4838 days ago | link

Thanks a lot! It's work now .

By the way, I've set my email in profile.

-----

1 point by akkartik 4838 days ago | link

Sorry, I meant set the email in your 'about' field. The 'email' field is only visible to the admins of the arc forum.

-----

1 point by Fenng 4838 days ago | link

OK.

I found another BUG, when click 'Saved' link in profile page, it's a blank page.

-----

1 point by akkartik 4836 days ago | link

Ah, you were right. Now fixed: https://github.com/nex3/arc/commit/ef519e72dd. Thanks a lot for catching this.

-----

1 point by akkartik 4838 days ago | link

Perhaps that's because you have nothing saved yet? It shows stories submitted by others that you've upvoted.

-----

1 point by akkartik 4841 days ago | link | parent | on: Cyclical data structures in arcueid

I'm flattered that you remember wart's nils :) And why would you imagine I care about compatibility?! Oh, you mean dido.

It's a good question whether you ever need cycles outside of these two scenarios. Hmm..

-----

2 points by Pauan 4840 days ago | link

"Oh, you mean dido."

Yes, my post was directed at dido.

---

"It's a good question whether you ever need cycles outside of these two scenarios."

I suppose there might be some algorithms that work better with mutable conses, but honestly, I think conses work best when they're functional, since they have a recursive definition. Making them mutable muddles a lot of different things with no real gain because you rarely mutate conses in Arc.

-----

2 points by akkartik 4842 days ago | link | parent | on: Cyclical data structures in arcueid

Hi dido, I have 2 comments:

1. Using a hash table for cycle detection can get prohibitive for large cycles. Fortunately there's Floyd's algorithm which detects cycles without the space overhead: https://en.wikipedia.org/wiki/Cycle_detection#Tortoise_and_h.... Here's how you might print an infinite list, one item to a line:

  -- z.wart
  def (print x hare)
    if ~list?.x
         prn x
       (addr.x = addr.hare)  # like arc's is
         prn '...
       (do (prn car.x)
           (print cdr.x (cdr+cdr (or hare x))))  # + is compose

  # create a cycle
  (<- x  '(1 2)
      lastcdr.x  x)

  prn (firstn 5 x)
  print x
To run it:

  $ git clone http://github.com/akkartik/wart
  $ cd wart
  $ git checkout f171a9d878    # Unnecessary except for visitors in the far future
  $ ./wart
  ready! type in an expression, then hit enter twice. ctrl-d exits.
  load "z.wart"
  (1 2 1 2 1)
  1
  2
  ...
2. You mentioned a couple of possible notations for cycles in lists. Here's my suggestion:

  (1 2 ...)    # means (1 2 1 2 ..)
This works especially well because wart uses ... for dotted lists:

  (1 ... 2)   # read as '1 consed with 2'
  (1 2 ...)   # read as '1 2 consed with itself'
Finally, you could represent more complex cycles as well:

  (1 2 ... (3 4 ...))    # (1 2 3 4 3 4 3 ..)

-----

2 points by rocketnia 4841 days ago | link

Both of the things you're talking about look specialized for cycles in flat lists. I think dido's examples could have just as easily used 'scar instead of 'scdr.

  arc> (= x '(1 2))
  arc> (scar x x)
  ((...) . 2)
  #0=(#0# . 2)
I do like the (1 2 ... (3 4 ...)) notation for cyclic lists though. :)

The Kernel R-1RK has a good approach to treating flat cyclic lists as though they're a usual case. IMO, it means everything that deals with lists is more complicated to explain and arguably doesn't even deal with "lists."

-----

2 points by dido 4839 days ago | link

Well, now that I consider it the real reason why I missed these cycle detection algorithms is that I've never thought of conses as being just lists. Sure, they're general enough to represent lists, and binary trees, but with the presence of scar and scdr, they are also capable of representing directed graphs with vertices of at most degree 2. In general, any Arc variable can be considered as a reference to a general directed graph (hash tables in particular can be considered vertices of arbitrary degree). Thus, pretty-printing an Arc variable boils down to traversing the graph it represents, and the traversal order that seems like it makes best sense here is depth-first search.

To do the #0=(#0# . 2) notation though seems like the traversal needs to be done twice, first to get the numeric assignments, and next to actually print them. Not sure if it can be done in one pass without making a tree of prettyprint fragments. A marshalling algorithm will need to do it that way though, I should think.

-----

2 points by akkartik 4841 days ago | link

You got me rereading R-1RK, and I was reminded again of how much I like the way Shutt connects up his design decisions to design goals and constraints. It's very in the spirit of Christopher Alexander (http://www.amazon.com/Notes-Synthesis-Form-Harvard-Paperback...).

In spite of the level of detail, kernel's design goals diverge so quickly from my own that I can't reuse any of the design work. It's really too bad.

Today's frustrating example: I really couldn't give a rat's ass that Kernel permits cyclical argument lists in operatives but not applicatives. Then in A.4 he talks about what's missing before R0RK, and the support for cycles feels pedantic next to the problem of a fast implementation. If he wasn't so concerned about handling cycles during eval perhaps the code wouldn't be slow. How the heck can a language be slower than wart?!

-----

1 point by akkartik 4841 days ago | link

Yes, the print example was just an illustration. It was also a good test for wart; I caught several bugs :) https://github.com/akkartik/wart/compare/686828edba...0e2388.... The tests are pretty self-contained.

I'd assumed I could apply Floyd's hare to handle cars as well, but you're right, now I'm not so sure. The key difficulty is that there's two dimensions, so does the number of hares double each iteration?

Here's a flat-cycle-detecting iso I've been playing with:

  def (iso a b)
    ((afn ((a harea|through) (b hareb|through))
      (if ~list?.a
            (a = b)
          (addr.a = addr.harea)
            (addr.b = addr.hareb)
          :else
            (and (iso car.a car.b)   # Can't detect cycles through car.
                 (self `(,cdr.a :through ,cdr+cdr.harea)
                       `(,cdr.b :through ,cdr+cdr.hareb)))))
      (list a :through cdr.a)
      (list b :through cdr.b))

-----

2 points by rocketnia 4838 days ago | link

"The key difficulty is that there's two dimensions, so does the number of hares double each iteration?"

Hmm. As the tortoise goes down branches, its location becomes indeterminate. As the hare goes down branches, its location becomes indeterminate relative to the tortoise, so we might need multiple hare markers per branch if we're doing a tortoise-directed search. If we try using the hare to direct the search instead, then we may still need to keep a growing history of hare locations on each branch so the tortoise can follow.

Either way, keeping a hash table sounds more straightforward to me.

Are you using this algorithm properly? I haven't seen any of your example code do a second pass to find out where the cycle begins and what its period is. But maybe you don't need to...?

-----

1 point by akkartik 4838 days ago | link

I'm just taking a constant-factor hit :) A few extra iterations doesn't change the result for either print or iso. And for cycles that loop back all the way to the start it turns out there's zero overhead.

  x <- '(1 2 3)
  lastcdr.x <- x  # 1 2 3 1 2 3 1 ...
  print x
  1
  2
  3
  ...  # exactly one iteration
But:

  x <- '(1 2 3)
  lastcdr.x <- cdr.x   # 1 2 3 2 3 2 3 ...
  print x
  1
  2
  ...

-----

2 points by rocketnia 4838 days ago | link

  You posted:
  
  x <- '(1 2 3)
  lastcdr.x <- cdr.x   # 1 2 3 2 3 2 3 ...
  print x
  1
  2
  ...
Is that the behavior you expect? I would expect "1 2 3 ...", but it looks like the rabbit and the hare meet at the (3 ...) cons and stop.

  1 2 3 2 3 2 3
  *              Print "1".
    * *          Print "2".
      *   *      Print "...".

-----

1 point by akkartik 4838 days ago | link

Yeah I tried it out before posting. I had to take pains in iso to make sure we do one full traversal. With print I didn't care as much.

Update: Ack, I found a bug in iso (http://arclanguage.org/item?id=17365):

  x <- '(1 2 3)
  y <- '(1 2 4)
  (do1 nil (<- lastcdr.x x lastcdr.y y))  # Avoid printing the cycles
  (iso x y)   # not nil!

-----

2 points by rocketnia 4838 days ago | link

Here's a slightly different bug I found before your update. It's another case where I don't know what behavior you expect, but it probably isn't this. :-p

  (do (a <- '(1 2 3)) (lastcdr.a <- cdr.a) nil)
  => nil
  (do (b <- '(1 2 3 2 3)) (lastcdr.b <- cdr.b) nil)
  => nil
  (not+not+iso a b)
  => nil
  (not+not+iso b a)
  => 1
(I'm using not+not+iso so it returns a predictable value rather than an address.)

-----

1 point by rocketnia 4838 days ago | link

"the rabbit and the hare"

Whoops. I didn't mean that. XD

-----

2 points by dido 4839 days ago | link

Interesting. I'd been looking around for cycle detection algorithms and knew I might have forgotten a simpler algorithm. I think that would do very nicely for the pretty printer and most likely the marshalling algorithm as well. We'll see if I can find a way to adapt it to work for iso as well, though on the face of it, it doesn't look that straightforward.

-----

1 point by Pauan 4839 days ago | link

Wikipedia has more algorithms for cycle detection:

https://en.wikipedia.org/wiki/Cycle_detection#Brent.27s_algo...

-----

1 point by akkartik 4839 days ago | link

As it happens I provided an implementation of iso at http://arclanguage.org/item?id=17365 :) Let me know if my toy language isn't clear. The basic idea is that you need two hare pointers, one for each arg.

-----

1 point by akkartik 4842 days ago | link | parent | on: Wart update: compose is now '+'

..which I've already taken off the table :)

-----

2 points by rocketnia 4841 days ago | link

I don't know what my point was in posting that link--I mulled over it for a long time before just posting what I'd typed in--and now I don't understand your reply. What did you take off the table, and when? ^_^;

-----

2 points by akkartik 4841 days ago | link

:) I assumed you were saying that wart wouldn't be able to include '+' in symbol names, but that was already true before this change. Wart has other constraints, but if you can use '&' for something you can also use '+'.

Does that trigger memories? Did I understand you right? Were you nostalgic for the good old days when wart symbols could include '+'? ^_^

-----

2 points by rocketnia 4841 days ago | link

"I assumed you were saying that wart wouldn't be able to include '+' in symbol names, but that was already true before this change."

Ah, point taken! You were already treating + as infix. Got it. ^_^

-----

1 point by akkartik 4845 days ago | link | parent | on: Number - Real

Anarki lets you escape down to scheme, so I've been doing just:

  ($.inexact->exact (/ 3 2))
Perhaps it's worth fixing this in coerce? Should exact or inexact be the default subtype for num?

-----

2 points by Pauan 4844 days ago | link

"Should exact or inexact be the default subtype for num?"

I see at least a few good solutions:

1) Use floating point everywhere. This is what JavaScript (and Nulan) do. Simpler, but it means you give up exact math on rationals.

2) Use floating point by default but support coercing to exact. This may or may not lose information, I don't know. Alternatively, support exact by default and coerce to floating point.

3) Do things the way Racket does it, but when printing the number, coerce it to floating point. This is what Arc/Nu does:

  > 3/2
  1.5
This has the benefit that math calculations are exact, but the result is printed in a more readable fashion (more readable to me anyways).

-----

1 point by akkartik 4844 days ago | link

Thanks, I ended up going with the third option, but with a twist: display prints inexact but write prints exact. So at the prompt you still see exact numbers:

  arc> (/ 3 2)
  3/2
  arc> (prn "aa: " (/ 3 2))
  aa: 1.5
https://github.com/nex3/arc/commit/a9dc15d701

-----

1 point by Pauan 4844 days ago | link

Well, the whole reason I did it in Arc/Nu was because I liked to use the REPL as a calculator, and I hated having it print rationals. So, having the REPL print rationals kinda defeats the point in my eyes, but I don't care since I don't use Anarki.

-----

2 points by akkartik 4843 days ago | link

Yeah, I don't actually want to see rationals at the prompt. It's just that lisp has this nice distinction between 'write and 'print, with the guarantee that 'read can handle anything 'write emits. I'm loath to have write+read change a value in subtle ways.

In this case, that the repl uses 'write is an unfortunate constraint. Still thinking..

-----

2 points by akkartik 4843 days ago | link

Update: I just realized my print solution sucks:

  arc> (prn (/ 3 2))
  1.5
  arc> (prn (list (/ 3 2)))
  (3/2)
Rolling it back. Let's just explicitly use real for now.

-----

3 points by jsgrahamus 4844 days ago | link

I vote for inexact.

-----

2 points by akkartik 4844 days ago | link

Hmm, I thought about it some more, and it seems worth preserving exact because you lose information in going to inexact.

The solution I ended up with was to use your name and Pauan's trick: https://github.com/nex3/arc/commit/4227a4a9b9.

Now instead of

  (coerce (/ 3 2) 'num)
You'd say:

  (real (/ 3 2))
What do you think? Easy to change if you prefer.

-----

1 point by Pauan 4844 days ago | link

Since that's being done in Anarki, I'd rather use $.exact->inexact, rather than relying upon Racket's auto-coercion. My trick is best used in Arc 3.1 which doesn't have (easy) access to Racket.

-----

2 points by akkartik 4844 days ago | link

Ok, done. For some reason I thought your trick was more permissive..

-----

2 points by jsgrahamus 4843 days ago | link

I like the (real (/ 3 2)) format. You easily get both.

-----

More