Arc Forumnew | comments | leaders | submitlogin

Good suggestion! We've bumped it up to 60 days.

Thank you.

Are you familiar with continuations? Continuations are essentially snapshots of the call stack. By calling (ccc ...), you take a snapshot. By calling the snapshot with a value, you jump back to that old stack -- right at the position of the (cc ...) call -- and return a different return value than before.

This is a pretty weird behavior, but it can useful for avoiding the inversion of control dilemma in imperative code. That is, if code A and B need to communicate, should code A call code B, or should code B call code A? Sometimes the callee side becomes a mess of callbacks, rather than a direct imperative style. With continuations, both sides can be the caller, and neither side needs to be the callee: When A calls B with a value, we resume B's earlier call to A using that value as the result. This approach doesn't make it straightforward to design communication paths that work like this, but it is a building block.

Unfortunately, jumping around with continuations messes up another common imperative coding technique. If people write code to set up and tear down a resource, they often like to write all the code in the middle in a way that assumes that resource is already available. With continuations, that assumption can be incorrect: If you jump out of the code in the middle, you may have just skipped the tear-down code entirely. If you jump into the middle, you may have just skipped the setup code.

Dynamic-wind makes up for that shortcoming by letting you write a structured code block that always executes its setup and tear-down sections, even if it's entered or exited using a continuation jump. So when you do a jump, you might actually go through a few dynamic-wind handlers before you reach your destination.

If you're more familiar with exceptions, continuations and dynamic-wind can be seen as a companion of exceptions and "try { ... } finally { ... }" blocks. An exception throw is a jump to an outer level of the stack, but the jump may stop to execute a few "finally" sections before it reaches its destination.

In Arc (and Scheme), continuations and exceptions are supported in the same language. They're both the same kind of jump, executing all the same handlers in between; the "finally" handlers and "tear-down" handlers are basically the same kind of handler. In Arc, unless you write custom Racket code to invoke Racket's dynamic-wind directly, Arc has no way to write a setup handler, but there is an (after ...) construct for writing a finally/tear-down handler.

I think what I've called "setup" and "tear-down" are more commonly called winding and unwinding handlers, or before and after sections. I picked the terms "setup" and "tear-down" just in the hopes of painting a more concrete picture of why they're useful.

This has still been a pretty quick explanation relative to the complexity of the topic, and I haven't included even a single example. If you still have unresolved questions, that's absolutely understandable. :)


What is dynamic-wind and why is it important?

Thanks, Steve

2 points by jsgrahamus 3835 days ago | link | parent | on: Using Arc at work

This probably seems weird, but I capture the data on a Windows system, then e-mail the data to a Linux system which is where arc resides. I assume Windows and Linux have different line endings.

Perhaps I need to check out the community version of arc?

Has anyone figured out a way to compile an arc routine? I saw an earlier thread on it, but no resolution.

Thanks for everything.

2 points by jsgrahamus 3835 days ago | link | parent | on: Using Arc at work

Thanks. Not sure what happened.
2 points by jsgrahamus 3835 days ago | link | parent | on: Using Arc at work

Thank you.
2 points by rocketnia 3836 days ago | link | parent | on: Using Arc at work

Judging by that error message, it looks like the variable "=" or one of its dependencies might have been reassigned somewhere along the line. The second argument in that error message indicates that = is getting hold of your read-in data somehow, so it might be something you've defined for processing this data.

The dependencies of = include expand=list, expand=, map, pair, and setforms (among others), so if any of these has been overwritten, it might do something like what you're seeing.

By the way, I think if you're not using Anarki, there's a known bug in (readline ...) where it will spuriously combine each empty line with the following line (https://sites.google.com/site/arclanguagewiki/arc-3_1/known-...). Maybe this could explain the extra \n you're getting.

1 point by akkartik 3836 days ago | link | parent | on: Using Arc at work

Hmm, not sure what happened. Not sure what you mean by memory problems, but I've never seen flakiness in a session this short. Perhaps something in your earlier session was accidentally a control character or something. Keep an eye out for it and I will too.

Here's a full session I tried out on linux:

  $ arc
  arc> (def printlst (thelist) (if (is thelist nil) (prn "") (do (prn (car thelist)) (printlst (cdr thelist)))))
  #<procedure: printlst>
  arc> (def readit () (drain (readline (stdin))))
  #<procedure: readit>
  arc> (= alist (readit))
  ARR(1)="PARSE    ; PARSE OUTPUT OF ^%RFIND INTO RSD/RTN/TAG"

  ARR(2)="         N ARR,FND,I,RSD,RTN,STOP,TXT"

  ARR(3)="         W !!,"PASTE""

  ARR(4)="         F  R !,X:15 Q:'$T  S ARR($I(ARR))=X"

  ARR(5)="         K RSDS"
  ("" "ARR(1)=\"PARSE    ; PARSE OUTPUT OF ^%RFIND INTO RSD/RTN/TAG\"" "" "ARR(2)=\"         N ARR,FND,I,RSD,RTN,STOP,TXT\"" "" "ARR(3)=\"         W !!,\"PASTE\"\"" "" "ARR(4)=\"         F  R !,X:15 Q:'$T  S ARR($I(ARR))=X\"" "" "ARR(5)=\"         K RSDS\"")
  arc> (printlst alist)

  ARR(1)="PARSE    ; PARSE OUTPUT OF ^%RFIND INTO RSD/RTN/TAG"

  ARR(2)="         N ARR,FND,I,RSD,RTN,STOP,TXT"

  ARR(3)="         W !!,"PASTE""

  ARR(4)="         F  R !,X:15 Q:'$T  S ARR($I(ARR))=X"

  ARR(5)="         K RSDS"

  ""
  arc> (= codes (obj "Boston" 'bos "San Francisco" 'sfo "Paris" 'cdg))
  #hash(("Boston" . bos) ("Paris" . cdg) ("San Francisco" . sfo))
  arc>
2 points by akkartik 3836 days ago | link | parent | on: Using Arc at work

Ah, yes tryarc would explain it.

By "the issue with the \n" do you mean how each line has a \n at the start? How is this sending data between Windows and Linux, can you elaborate?

Yes, it's weird that you had to hit ctrl-d twice. Thanks. I'll try your example on windows later today.

Both these issues aren't happening for me on linux, so it seems likely to be a windows issue.

Edit: Hmm, I do see a leading empty list at the start when reading stdin:

  arc> (readit)
  abc
  def
  ("" "abc" "def")
It looks like stdin doesn't behave quite like a regular file handle.. Thanks for the report! I'll investigate why this is happening.

Edit 2: The trouble seems to be that the first call to 'readline' receives the 'enter' you hit to type in the command.

  arc> (readline (stdin))
  ""
  arc>
I think your examples might work if you put the code into a .arc file and try to run it like my original example..
2 points by jsgrahamus 3836 days ago | link | parent | on: Using Arc at work

Followon #2

Stopped arc and restarted it and had no problems with obj

How prone is arc to memory problems?

2 points by jsgrahamus 3836 days ago | link | parent | on: Using Arc at work

Here is a follow on problem as I'm going through the tutorial: obj does not work and the error message seems to access memory not involved with the obj.

  arc> (printlst alist)

  ARR(1)="PARSE    ; PARSE OUTPUT OF ^%RFIND INTO RSD/RTN/TAG"

  ARR(2)="         N ARR,FND,I,RSD,RTN,STOP,TXT"

  ARR(3)="         W !!,"PASTE""

  ARR(4)="         F  R !,X:15 Q:'$T  S ARR($I(ARR))=X"

  ARR(5)="         K RSDS"



  ""
  arc> (= codes (obj "Boston" 'bos "San Francisco" 'sfo "Paris" 'cdg))
  Error: "list-ref: contract violation\n  expected: exact-nonnegative-integer?\n  given: '(((codes (obj \"Boston\" (quote bos . nil) \"San Francisco\" (quote sfo . nil) \"Paris\" (quote cdg . nil) . nil) . nil) . nil))\n  argument position: 2nd\n  other arguments...:\n   '(\"\\nARR(1)=\\\"PARSE    ; PARSE OUTPUT OF ^%RFIND INTO RSD/RTN/TAG\\\"\" \"\\nARR(2)=\\\"         N ARR,FND,I,RSD,RTN,STOP,TXT\\\"\" \"\\nARR(3)=\\\"         W !!,\\\"PASTE\\\"\\\"\" \"\\nARR(4)=\\\"         F  R !,X:15 Q:'$T  S ARR($I(ARR))=X\\\"\" \"\\nARR(5)=\\\"         K RSDS\\..."
  arc>
2 points by jsgrahamus 3836 days ago | link | parent | on: Using Arc at work

Perhaps it was because I was using tryarc.org?

So I tried again with arc running on Racket under Linux. Here's what I found:

  arc> (def readit () (drain (readline (stdin))))
  #<procedure: readit>
  arc> (readit)
  ARR(1)="PARSE    ; PARSE OUTPUT OF ^%RFIND INTO RSD/RTN/TAG"

  ARR(2)="         N ARR,FND,I,RSD,RTN,STOP,TXT"

  ARR(3)="         W !!,"PASTE""

  ARR(4)="         F  R !,X:15 Q:'$T  S ARR($I(ARR))=X"

  ARR(5)="         K RSDS"

  ("\nARR(1)=\"PARSE    ; PARSE OUTPUT OF ^%RFIND INTO RSD/RTN/TAG\"" "\nARR(2)=\"         N ARR,FND,I,RSD,RTN,STOP,TXT\"" "\nARR(3)=\"         W !!,\"PASTE\"\"" "\nARR(4)=\"         F  R !,X:15 Q:'$T  S ARR($I(ARR))=X\"" "\nARR(5)=\"         K RSDS\"" "\n")
  arc> (= alist (readit))
  ARR(1)="PARSE    ; PARSE OUTPUT OF ^%RFIND INTO RSD/RTN/TAG"

  ARR(2)="         N ARR,FND,I,RSD,RTN,STOP,TXT"

  ARR(3)="         W !!,"PASTE""

  ARR(4)="         F  R !,X:15 Q:'$T  S ARR($I(ARR))=X"

  ARR(5)="         K RSDS"

  ("\nARR(1)=\"PARSE    ; PARSE OUTPUT OF ^%RFIND INTO RSD/RTN/TAG\"" "\nARR(2)=\"         N ARR,FND,I,RSD,RTN,STOP,TXT\"" "\nARR(3)=\"         W !!,\"PASTE\"\"" "\nARR(4)=\"         F  R !,X:15 Q:'$T  S ARR($I(ARR))=X\"" "\nARR(5)=\"         K RSDS\"" "\n")
  arc> alist
  ("\nARR(1)=\"PARSE    ; PARSE OUTPUT OF ^%RFIND INTO RSD/RTN/TAG\"" "\nARR(2)=\"         N ARR,FND,I,RSD,RTN,STOP,TXT\"" "\nARR(3)=\"         W !!,\"PASTE\"\"" "\nARR(4)=\"         F  R !,X:15 Q:'$T  S ARR($I(ARR))=X\"" "\nARR(5)=\"         K RSDS\"" "\n")
  arc> (len alist)
  6
  arc> (def printlst (thelist) (if (is thelist nil) (prn "") (do (prn (car thelist)) (printlst (cdr thelist)))))
  #<procedure: printlst>
  arc> (printlst alist)

  ARR(1)="PARSE    ; PARSE OUTPUT OF ^%RFIND INTO RSD/RTN/TAG"

  ARR(2)="         N ARR,FND,I,RSD,RTN,STOP,TXT"

  ARR(3)="         W !!,"PASTE""

  ARR(4)="         F  R !,X:15 Q:'$T  S ARR($I(ARR))=X"

  ARR(5)="         K RSDS"



  ""
  arc>                                                   
I think the issue with the \n is sending data between Windows and Linux.

I did have to key in Ctrl-D twice to actually get the function to finish reading. Is there a better way to do this?

Thanks for all of the help with this.

Steve

1 point by akkartik 3836 days ago | link | parent | on: Using Arc at work

I don't follow. You got this message when you tried my code snippet? That seems really strange!
2 points by jsgrahamus 3836 days ago | link | parent | on: Using Arc at work

  Unknown or expired link.
In the example above the READ X:5 or 15, allowed the read 5 or 15 seconds before timing out. I wonder if that is what we are seeing here.

Thanks for the help.

1 point by akkartik 3837 days ago | link | parent | on: Using Arc at work

Sorry, typed that out on my phone without trying it out. You need parens around stdin.

  (drain (readline (stdin)))
Alternatively:

  (write:drain:readline:stdin)
2 points by jsgrahamus 3837 days ago | link | parent | on: Using Arc at work

  Error: "read-char: expects argument of type <input-port>; given #<procedure:current-input-port>"
1 point by akkartik 3837 days ago | link | parent | on: Using Arc at work

Great! Then you should be able to drop the outer w/infile form and just say:

  (drain (readline stdin))
2 points by jsgrahamus 3837 days ago | link | parent | on: Using Arc at work

The program will read lines of data from stdin and print each of them.

Thanks for the reminder.

How does one do, what you posted, when the input is from the keyboard buffer and not from a file?

2 points by akkartik 3837 days ago | link | parent | on: Using Arc at work

I'm still not following what your program does. (Can you describe its inputs and how it transforms them in english?)

I remember you asked a similar question last year: http://arclanguage.org/item?id=19109. Perhaps it would help to connect up how your question here relates to that thread?

Here's how you run the code in that thread for reading lines from a file with anarki:

  $ cat x
  ab
  cd ef
  ghi

  $ cat x.arc 
  (write:w/infile file "x"
    (drain (readline file)))

  $ ./arc x.arc
  ("ab" "cd ef" "ghi")
  #t
1 point by jsgrahamus 3837 days ago | link | parent | on: Using Arc at work

This is the line of code above slightly modified

  KILL ARR FOR I=1:1 READ !,X:5 QUIT:'$TEST  SET ARR(I)=X
(Press Shift-Insert or Ctr-V or whatever to insert buffer)

  PARSE    ; PARSE OUTPUT OF ^%RFIND INTO RSD/RTN/TAG
           N ARR,FND,I,RSD,RTN,STOP,TXT
           W !!,"PASTE"
           F  R !,X:15 Q:'$T  S ARR($I(ARR))=X
           K RSDS
           S STOP=0,I=1 F  S RTN=$P(ARR(I),".") D  Q:STOP
           . F  S I=$O(ARR(I)) S:I="" STOP=1 Q:STOP  Q:ARR(I)?1.AN1".".E  D
           . . S TXT=ARR(I),FND=$F(TXT,"RSD ")
           . . I FND D
           . . . S RSD=$P($E(TXT,FND,999)," ")
           . . . S RSDS(RSD,RTN_"^"_$P(TXT,"+"))=""
           W !!
           S RSD=""
           F  S RSD=$O(RSDS(RSD)) Q:RSD=""  D
           . W !!,RSD
           . S RTN=""
           . F  S RTN=$O(RSDS(RSD,RTN)) Q:RTN=""  D
           . . W !?5,RTN
           Q
           ;
  FIND     ;
           N CTR,I,RTN,STR,TAG,TXT
           R !!,"STRING: ",STR Q:STR=""
           R !,"ROUTINE: ",RTN Q:RTN=""
           F I=1:1 S TXT=$T(+I^@RTN) Q:TXT=""  D
           . I TXT?1(1AN,1"%").E D
           . . S TAG=$P($P($P(TXT," "),$C(9)),"("),CTR=0
           . E  D
           . . S CTR=CTR+1
           . I TXT[STR W !,TAG W:CTR "+",CTR W ?14,TXT
           Q
           ;
Entering the next line will show the contents of the array:

  ZWRITE ARR

  ARR(1)="PARSE    ; PARSE OUTPUT OF ^%RFIND INTO RSD/RTN/TAG"
  ARR(2)="         N ARR,FND,I,RSD,RTN,STOP,TXT"
  ARR(3)="         W !!,"PASTE""
  ARR(4)="         F  R !,X:15 Q:'$T  S ARR($I(ARR))=X"
  ARR(5)="         K RSDS"
  ARR(6)="         S STOP=0,I=1 F  S RTN=$P(ARR(I),".") D  Q:STOP"
  ARR(7)="         . F  S I=$O(ARR(I)) S:I="" STOP=1 Q:STOP  Q:ARR(I)?1.AN1".".E  D"
  ARR(8)="         . . S TXT=ARR(I),FND=$F(TXT,"RSD ")"
  ARR(9)="         . . I FND D"
  ARR(10)="         . . . S RSD=$P($E(TXT,FND,999)," ")"
  ARR(11)="         . . . S RSDS(RSD,RTN_"^"_$P(TXT,"+"))="""
  ARR(12)="         W !!"
  ARR(13)="         S RSD="""
  ARR(14)="         F  S RSD=$O(RSDS(RSD)) Q:RSD=""  D"
  ARR(15)="         . W !!,RSD"
  ARR(16)="         . S RTN="""
  ARR(17)="         . F  S RTN=$O(RSDS(RSD,RTN)) Q:RTN=""  D"
  ARR(18)="         . . W !?5,RTN"
  ARR(19)="         Q"
  ARR(20)="         ;"
  ARR(21)="FIND     ;"
  ARR(22)="         N CTR,I,RTN,STR,TAG,TXT"
  ARR(23)="         R !!,"STRING: ",STR Q:STR="""
  ARR(24)="         R !,"ROUTINE: ",RTN Q:RTN="""
  ARR(25)="         F I=1:1 S TXT=$T(+I^@RTN) Q:TXT=""  D"
  ARR(26)="         . I TXT?1(1AN,1"%").E D"
  ARR(27)="         . . S TAG=$P($P($P(TXT," "),$C(9)),"("),CTR=0"
  ARR(28)="         . E  D"
  ARR(29)="         . . S CTR=CTR+1"
  ARR(30)="         . I TXT[STR W !,TAG W:CTR "+",CTR W ?14,TXT"
  ARR(31)="         Q"
  ARR(32)="         ;"
This is the functionality I wish to clone. Doesn't amtter to me if lists are used instead of arrays.
3 points by aw 3837 days ago | link | parent | on: Capturing the Dynamic Environment

Thanks!

I think for it to be a good tutorial, it ought to do something that's useful on its own. Maybe an implementation of generators or something like that. `capture-dyn` is a useful tool for working with continuations (it seems like), but I think as a tutorial it may be a bit esoteric since you'd already need to know about the interaction of continuations with dynamic scope to see when and why you'd want to use `capture-dyn`.

2 points by akkartik 3837 days ago | link | parent | on: Capturing the Dynamic Environment

This was surprisingly easy to follow considering I was rusty on ccc; I didn't need to consult the definition of ccc because your descriptions made it easy to deduce. Maybe this also makes it a nice tutorial for ccc?!

Another reaction: I wish there was a way to encode such 'derivations' of code in code, so it could lie in arc.arc without seeming inscrutable. It's only inscrutable without your accompanying prose.


Store-passing style! I've been using it in my programs too. It even came up again on David Barbour's blog yesterday.[1] It's kinda funny how everything keeps coming back to the same continuation-passing styles and store-passing styles.

I think I've followed all these to a nice, general conclusion in Staccato. :)

Staccato's going to have at least two completely different (and not necessarily compatible) families of side effects: At compile time, macros will install definitions as a form of side effect. At run time, microservices will have continuous reactive side effects for communicating with each other. Nevertheless, I'm taking one consistent approach to side effects that should work in both cases. (It might be pretty inefficient when used for continuous reactive effects, but I'm optimistic.)

Staccato has no static type system (yet?), but even if it did, I would expect to have to think about run time errors anyway: Usually, a program can be written that bides its time until the Earth gets consumed by the sun, and then there's no way it'll successfully proceed to return a value. So, I accept dynamic errors, but I'll be mindful of where and when any given error could gum up the works, e.g. whether it happens on the browser side or the server side, and whether it happens before or after some other side effects occur.

So the kind of purity I'm going for involves quasi-determinism in the sense I've seen Lindsey Kuper use it when talking about LVars[2]: As long as a program isn't swallowed by the sun or otherwise interrupted, it will always return the same value. I'll still need to be mindful of where and when errors may occur in the language (e.g. server-side or client-side), so that I know which of the program's side effects should be aborted or reverted.

If a "side effect" only communicates with the language implementation itself (e.g. for debugging or profiling), that's fine. We already trust the language implementation to implement the language semantics in a single deterministic way, so we can trust it to respond to these communications in a single deterministic way as well!

If a "side effect" is tame enough that it can be removed by dead code elimination if the result value is never used, that's fine too. Arguably it has no side effects at all; the effects are all represented in its result. This means there can be some minimal support for operations that read some value from an opaque external reference (e.g. a file handle, a socket). In order to preserve quasi-determinism, the output may only vary if the input does, so these operations will tend to take an explicit parameter designating the time/world at which to do the reading. If a program makes pervasive use of these operations, it will take the shape of a sort of store-passing style, though it doesn't ever need to return a new version of the store. (For context: Whereas Haskell's State monad is used for store-passing style, its Reader monad is simplified for this special case.)

I'll do all other side effects using a commutative monad. By commutativity, any two commands in this monad can be reordered, which should guide me toward easy refactoring, extensibility, and concurrency. If I need to write any code that depends on the result of an effect, this can't usually be done in a commutative way, but a commutative effect could still set up an asynchronous callback, which can run a separate set of commutative effects in a future tick. If a computation spans more than a few of these ticks, it'll start to look like continuation-passing style. Staccato's syntax is actually pretty nice for continuation-passing style code, so this isn't a problem. CPS necessarily sequentializes the code, but when I need concurrency, I can synchronize between concurrent code the way JavaScript programmers often do these days, using promises.[3]

[1] https://awelonblue.wordpress.com/2016/01/04/yield-for-effect...

[2] http://composition.al/blog/2013/09/22/some-example-mvar-ivar...

[3] To preserve quasi-determinism and to ensure that no two promise allocations give the same promise as their result, the allocation of a promise will itself be an asynchronous operation. (This is sort of a note to myself, because I haven't written up designs for the promise primitives yet.)

2 points by aw 3839 days ago | link | parent | on: A Functional Implementation of Dynamic Scope

Sounds like it. The idea is that you have some irreducible amount of imperative state out in the "real world" (files in the OS, your hardware screen, etc), and the goal is to keep that as small a part of your language as possible -- so that the rest of your language can be as functional as possible.

This raises a question I've been mulling for a year now: is a global variable just an implicit parameter passed into all functions? What does 'functional' really mean? I've been exploring new interfaces at the lowest levels of the OS that make all operations referentially transparent without any constraints on mutability. For example, the 'print' syscall takes a screen object as an ingredient. (The real hardware screen is represented as nil/0.) Is that as 'functional' as Haskell?
2 points by highCs 3866 days ago | link | parent | on: Threads

What I could do however, is have a master process starts an http server with a daemon-less database. At this point, one can read and write the database at any time via http requests. Then I can make the worker processes thing works. Then Arc has parallelism.
2 points by highCs 3867 days ago | link | parent | on: Threads

Sophia doesn't allow multiple processes to access the same databse.
2 points by highCs 3869 days ago | link | parent | on: Threads

Since sqlite is daemon-less, it doesnt work well when multiple processes try to access the same database; one starts receiving database locked errors. I'll see if I can find a daemon-less database engine which handles that. I want to run multiple arc http servers accessing a single database behind a load-balancer and I want a client app to have parallelism using worker processes, which would use the same kind of database engine. So I'm looking for a daemon-less database engine that multiple processes can access concurrently without me having to implement anything to support that and which works under windows, linux and OSX. Anyone knows one? I'm looking at Sophia right now [1]

[1] http://sphia.org/

3 points by highCs 3869 days ago | link | parent | on: Threads

Oh I get it I think. Futures are for computing arithmetic in parallel.
More