Arc Forumnew | comments | leaders | submitlogin
1 point by Pauan 4763 days ago | link | parent

Why? `t` is a nice and short variable name, and I would expect it to work fine in function arguments. Hm...

  ((fn (t) t) 10)         -> 10
  ((fn (quote) quote) 10) -> 10
  ((fn (nil) nil) 10)     -> nil
Seems nil doesn't like being shadowed. Works fine in my interpreter, though: they all return 10.


1 point by rocketnia 4763 days ago | link

"Seems nil doesn't like being shadowed."

That's because ((fn (nil) nil) 10) is supposed to be the same as ((fn (()) nil) 10), which destructures the first 0 elements from 10, treating it as a degenerate cons list.

I actually use this behavior in practice, 'cause it's useful to have at least some parameter syntax that doesn't bind any variables, rather than just using a conventional name like "ignored" or "_". Most of the time I use it in a much-too-big 'withs block, where I abuse one of the bindings for sanity-checking or other side effects. ^^ I wouldn't worry about it too much, though.

On the other hand, nil's behavior makes it more verbose to determine whether something's usable as a local variable; you have to check (and x (isa x 'sym) (~ssyntax x)). In Lathe, I define 'anormalsym to do just that. (It might be more accurate to change it to (and (isa x 'sym) (~in x nil t 'o) (~ssyntax x)).)

Speaking of (~ssyntax x), ssyntax is usable for local variable names, but naturally, you can only get the values from the Racket side:

  arc> (let a.b 4 a.b)
  Error: "reference to undefined identifier: _a"
  arc> (let a.b 4 ($ a.b))
  4
That could be a bug.

Personally, I'd like for ssyntax-burdened names in parameter lists to use user-defined parameter syntaxes, like custom forms of destructuring and whatnot. And then, just for axiomatic simplicity's sake, I'd like things like 'o to be implemented using the same system, using ssyntax-burdened names like ".o".

-----

1 point by Pauan 4763 days ago | link

"That's because ((fn (nil) nil) 10) is supposed to be the same as ((fn (()) nil) 10)"

nil is such a weird value... it's false, a symbol, and an empty list all at once. I actually had to do some hacky stuff to get () and '() and nil to behave properly.

"Speaking of (~ssyntax x), ssyntax is usable for local variable names, but naturally, you can only get the values from the Racket side:"

I plan to implement ssyntax at the reader level in my interpreter, so that shouldn't be an issue.

-----

1 point by evanrmurphy 4763 days ago | link

"nil is such a weird value... it's false, a symbol, and an empty list all at once."

Perhaps nil should serve as the base case for every type, rather than just some of them. In Arc, it already does this for booleans, lists and strings (""), but it could be extended to support tables (#hash()), numbers (0), symbols (||) etc. Then it would have more consistency as a concept.

-----

2 points by shader 4763 days ago | link

I've run into issues with nil the symbol vs nil the value. It's caused some issues when I wanted to use arc's sym type to represent variable names in a class compiler project I'm working on. If the variable's name is nil, all kinds of things stop working, and I've had to resort to calling some scheme functions directly to get proper handling of symbols.

I wish that 'nil and nil could be kept somewhat separate, with the first being just a symbol, and the second being equivalent to the base value for all data structures. Otherwise the symbol type is broken and inconsistent, since you cannot accurately (or at least completely) represent code as data.

-----

2 points by Pauan 4762 days ago | link

My interpreter treats 'nil and nil as separate. Not sure if that's a good idea, but I'd rather wait and see if it causes problems before changing it:

  (is 'nil nil) -> nil
This does raise one interesting question, though... obviously 'nil is a sym, but if (is nil ()) is t, then shouldn't (type nil) return 'cons?

-----

2 points by waterhouse 4761 days ago | link

() is not a cons cell, and while (car ()) is well-defined (to be nil), you can't set the car or cdr of (). It is definitely not a cons.

On the other hand, (listp nil) should be true. In fact, its precise definition should probably be (and is, or is equivalent to) this:

  (def listp (x)
    (or (is x nil)
        (and (acons x)
             (listp (cdr x)))))

-----

1 point by Pauan 4760 days ago | link

However, I can easily define nil so that it's type is 'cons, but it would throw an error if you try to assign to the car or cdr. That may break code that assumes that 'cons != nil though.

Actually, I could represent nil as an actual 'cons cell, so that assigning to the car or cdr would work. Crazy? Probably. Especially since nil is a singleton and you can't create more nil's, so it would be a global change.

Right now, nil does have a type of 'sym, but it seems weird to treat it mostly like an empty cons cell, but not have it's type be 'cons. So I figured I could play around with it and try giving it a type of 'cons and see how badly it breaks stuff.

-----

2 points by evanrmurphy 4760 days ago | link

"Actually, I could represent nil as an actual 'cons cell, so that assigning to the car or cdr would work. Crazy?"

That's a bit crazy. :)

PicoLisp does something reminiscent. Every one of its data structures (numbers, symbols, nil and conses) is implemented using the low-level cons cell structure (i.e. a pair of machine words). [1] They talk about nil's representation fulfilling its dual nature as both a symbol whose value is nil and a list whose car and cdr are nil; both the symbol predicate and the list predicate return true when applied to nil:

  : (sym? NIL)
  -> T
  : (lst? NIL)   
  -> T
I'm not sure that they let nil's car and cdr be assignable though, because "NIL is a special symbol which exists exactly once in the whole system." [2]

--

[1] http://software-lab.de/doc/ref.html#vm

[2] http://software-lab.de/doc/ref.html#nilSym

--

Update: Oops, I just noticed a lot of this comment could be considered redundant with the grandparent comment by waterhouse. Sorry for that.

-----

1 point by rocketnia 4763 days ago | link

My code has a lot of [string:or _ "nil"] to handle that kind of stuff. ^_^ I've just kinda accepted it ever since http://arclanguage.org/item?id=10793.

I do 'string lists into strings a lot, but that would continue to work if 'nil and '() were separate values.

-----

1 point by aw 4763 days ago | link

If the variable's name is nil, all kinds of things stop working

Can you give an example? Are you trying to use nil as a variable name in Arc, or simply to have a data structure representing variables where some of those variables are named nil?

-----

1 point by shader 4761 days ago | link

I'm creating a compiler for a class, and I've been representing variable names in the ast with symbols. I could use strings instead, and may end up doing so, but symbols seemed a more elegant solution.

-----

1 point by Pauan 4763 days ago | link

So nil would be an ubertype that basically just means "empty"? One issue with that is (is 0 nil) would be t... I think it's useful to not always treat 0 as the same as nil.

Not sure about empty tables, though... maybe it would be fine to treat those as nil. We already treat an empty list as nil, after all.

Actually, what you're suggesting is very similar to how languages like JavaScript and Python do it, with 0 null undefined NaN "" etc. being falsy. So in JS, you can do this:

  var foo = 0;
  if (foo) {} // will not be evaluated

  foo = "";
  if (foo) {} // will not be evaluated

  foo = NaN;
  if (foo) {} // will not be evaluated
On the other hand, both those languages support actual Booleans, and they treat an empty array as true.

-----