vrk


12 points by vrk over 2 years ago | link
cached 5 days ago

9 points by vrk over 2 years ago | link
cached 2 days ago

6 points by vrk over 2 years ago | link | top
cached 3 days ago
> Embedding docstrings in with the source also imply that functions and macros should be documented as they are written

This is how it should always be done. Encoding your ideas in any programming language is a lossy operation: it's difficult or impossible to determine from an arbitrary piece of source code what the intent and purpose of the programmer originally was. Good documentation gives the missing pieces.

I've found it incredibly helpful to write the documentation of functions before the function itself. Like you, I have a small head, and unless I know exactly what I should program beforehand, it's going to be difficult and messy to keep all details in mind. Describe the intent and purpose, give a canonical example of use (single line, or a couple of more if the function is variadic), rule out illegal input, and you're set.

Note that I'm not advocating long pieces of documentation. If you cannot describe a function well in a few lines, it's too big, and it's definitely not clear to you what it should be. If the documentation is in the same place as the source code, it is worlds easier to write the documentation, write the source code, then bounce between them while developing (since both usually require iteration).

I do not want to see idiotic documentation in Arc programs, but I doubt people who pick up Arc would do that anyway. I've seen many systems written in, e.g., Java, where documentation follows the same pattern as many Microsoft application help systems: "If you press the button called Print, you can print the document." or "Check here to enable grayscale printing" as a tooltip to a checkbox called "Enable grayscale printing".


6 points by vrk over 2 years ago | link | top
cached 2 days ago
Talk about ultimate hacker language: every hacker has his own version. Not a bad idea to try, though.

5 points by vrk over 2 years ago | link | top
cached 5 days ago
I disagree. x.y should remain (x y). It's plain confusing if you make it look like the dot notation in "object-oriented" languages, when it clearly is not. It's just an alternative way to write function application!

It would make more sense to provide the following kind of implicit currying:

  (def f (x y) ...)
  (let (x 'something)
    (= curried-f f.x))

  curried-f!else ; Calls (f 'something 'else)
Besides, if you switched the arguments or otherwise limited the usefulness of the new syntax to "(obj.f x1 x2)", you could never chain as in "f.obj.x1.x2"; instead, you would need to write "x2.x1.obj.f", which looks ridiculous.

I'm in favour of the dot syntax as infix function application operator. It reminds me of Edsger Dijkstra's reasoning (in fact, he also used the dot as function application). You may want to read [1] for the full story and other nice pondering about infix operators and syntax.

[1] http://www.cs.utexas.edu/~EWD/transcriptions/EWD13xx/EWD1300...


5 points by vrk over 2 years ago | link | top
cached 5 days ago
Is the prefix notation the biggest reason Lisp is not used more? No, I don't think so. Prefix, infix, or postfix is all a matter of what you are used to. It's possible to define the max operator as infix instead of prefix:

  (max 1 2) ; --> 2
  1 max 2   ; --> 2
It's associative (it's easy to prove). And after that you can do the regular stuff:

  1 max 3 max 2 max 5 ; --> 5 
Does this look natural? Usually max is more of a function, or in mathematics one usually writes

  max{  }
or with set comprehension

  max{ x :  } .
I find infix max easier in pen-and-paper calculations.

Coming back to Lisp and Arc, is familiarity the only reason you want infix math operators? The biggest benefit you get from prefix compared to infix is its regularity and uniformity. Control structures, function calls, and (now in Arc) array and hash table access are all identical. This means you can freely add not only new functions, but new control structures, without hacking the parser and the compiler.

One reason why this happens is that you don't have precedence levels. Precedence is always explicit (bar Arc's new intrasymbol operators, which are infix), and this is why Lisp mathematical functions, such as + and *, accept multiple arguments. The distinction between (+ 1 (+ 2 3)) and (+ (+ 1 2) 3) is useless and even harmful. It's best to write it (+ 1 2 3) or 1 + 2 + 3, because the operation is associative.

Aside from losing this, you also lose the concept that your whole program is a list. This stands at the heart of Lisp macros. How would you write macros for opaque infix blocks?


4 points by vrk over 2 years ago | link
cached 7 days ago

3 points by vrk over 2 years ago | link | top
cached 9 days ago
You may want to consider something non-traditional in Lisp circles: infix functions. Let me elaborate (and use the proposed new angle bracket syntax).

The "f:g" syntax is a nice idea for function composition, as is "~f" for negation, but the current syntax and semantics seem like a hack. What if we could do this instead:

  (def f (x y) ...)
  (infix f left)

    ; The compiler would transform this to (f x y)
    ; And this to (f (f x y) z) (evaluate from the left)

  (infix f right)

    ; And now to (f x (f y z)) (evaluate from the right)

  ; Use in "normal" syntax:
  (= foo )  ; --> (= foo (f x y))

  ; So, we could do this:
  (infix + right)
  
  (= foo <1 + 2>)  ; Would evaluate/transform to (= foo (+ 1 2))

  (= foo (+ 1 2 3 4))  ; And we could still use the ordinary function call syntax.

  ; Or maybe even:
  (infix + associative)
  (= foo <1 + 2 + 3 + 4>)  ; Transforms to (+ 1 2 3 4) if the function is n-ary, or 
                           ; some arbitrary evaluation order if not.

  ; And now for the interesting bit.
  (def : (f g) (fn (x) (f (g x)))))
  (infix : right)

  (map  list)  ; What currently is (map f:g list)

  ; Why not extend the idea?
  (def ~ (f) (fn (x) (not (f x))))
  (unary ~)

  (if (<~ predicate> arg) ...)

  ; No, that doesn't have any benefit over ((~ predicate) arg).
Problems:

- How do you define precedence levels? Once you are in this swamp, you can't get out. Maybe all infix functions would have the same precedence to side-step the issue.

- Is it possible to do with only the < > notation? But how would you parse the following without the additional information that + is infix?

  <+ + + + +> 
- Is it worth the two more characters and whitespace?

3 points by vrk over 2 years ago | link | top
cached 6 days ago
I would see more value in making a documention generating macro, so that you could easily keep the documentation and program code in one place, not unlike Perl POD and JavaDoc.

  (doc ""
    (def fun args ...))
In normal compilation, the doc macro would simply return the function definition, but it could be defined to generate, say, LaTeX or HTML, or a DOM tree that could be rendered using an arbitrary markup language. The difficulty is identifying the type of code that is enclosed in the doc block, as if you want to extend the paradigm to non-function definitions, or arbitrary macros even, it's going to get hairy.

3 points by vrk over 2 years ago | link | top
cached 6 days ago
This make me ask, would it be possible and reasonable to make a rudimentary foreign-function interface using TCP sockets and serializing data to strings, instead of reinventing the FFI wheel again? True, it would be inefficient, but it would not be too difficult to do (say, using YAML [1] as the serialization format), it would give access to many libraries fast, and as a bonus you could run the library service remotely.

Ferrying complex objects with binary data over the link is not going to be pleasant in that scheme, though. And it would be difficult to conceive a generic function call protocol without reinventing RPC or SOAP.

[1] http://www.yaml.org/