hylang / hyrule

A utility library for Hy
MIT License
43 stars 9 forks source link

"inc" naming #7

Open Quelklef opened 5 years ago

Quelklef commented 5 years ago

IMO, inc is poorly named. I had thought that (inc x) is (+= x 1) when it, in fact, is (+ x 1). "increment" seems to imply a mutative statement.

I suggest that (inc x) be (+= x 1) and (succ x) be (+ x 1). Similarly, (dec x) should be (-= x 1) and (pred x) be (- x 1).

This would be in line with:

Kodiologist commented 5 years ago

Sounds like a good idea to me. We were following Clojure here, but Common Lisp's interpretation makes more sense to me.

Kodiologist commented 5 years ago

Actually, if we do that, perhaps we should use Common Lisp's names, incf and decf, so as not to trip up Clojure programmers.

Quelklef commented 5 years ago

Eh, incf and decf are fairly ugly names, IMO. I personally would like inc! and dec! but as far as I can tell, Hy doesn't use that convention.

Another option would be to not have mutative increment/decrement functions. (+= x 1) and (-= x 1) are not that bad to write, and while succ and pred are likely to be passed around a lot in functional code, saving many keystrokes over (fn [x] (+- x 1)), I imagine that mutative increment/decrement functions will only be used as statements, not saving that much at all.

yuhan0 commented 5 years ago

+1 to not changing the existing meaning of inc / dec to be mutative. (as someone coming from Clojure and also very new to Hy)

Using incf from Common Lisp doesn't make much sense because there's no equivalent concept in Hy of a "generalized place variable"...

Maybe incv / decv in relation to setv ?

(defmacro incv [x]
  `(+= ~x 1))

(setv xs [1 2 3])
(incv (get xs 2))
(print xs)
;; => [1, 2, 4]
Kodiologist commented 5 years ago

there's no equivalent concept in Hy of a "generalized place variable"

But there is; it's the same concept of lvalue that Python uses. Just as you can put a variety of things to the left of = in Python other than plain variables, you can do the same in Hy with setv.

Quelklef commented 5 years ago

I'm betting that setv was only called what it was because Python has the built-in set function (@Kodiologist confirm?) so I'm not sure making -v a motif would be great.

Quelklef commented 5 years ago

Personally I think it would be cool to do this as follows:

doto transforms mutative forms into non-mutative forms. What if there was a counterpart, called, say, #!?

(setv x 1)
#! (succ x)  ; expands to (setv x (succ x))

(setv l [5 4 3 2 1])
#! (sorted l)  ; expands to (setv l (sorted l))

This would be a more general solution, bridging the mutative<->non-mutative gap in the other direction, which would be awesome. However, it's a little weird/hard to read. Also, the examples I gave are very simple and it's not clear how it should generalize to multiple values or multiple forms (if desired).

Kodiologist commented 5 years ago

I'm betting that setv was only called what it was because Python has the built-in set function (@Kodiologist confirm?)

It looks like it (73695881a9b69bab9d10a356258e78cf0ec6afa3).

Yeah, it's not clear how #! would detect the lvalue in general.

Quelklef commented 5 years ago

A solution would be to make it not a tag, so you'd have:

(mut a (succ))
(mut b (sorted))
(mut c (filter even?))

; Multiple forms?
(mut d (map succ) (filter even?))

where the supplied argument is the last argument.

yuhan0 commented 5 years ago

Personally I actually like the -v prefix as a sort of reminder that it follows Python's scoping rules, as opposed to the setq in other Lisps.

@Quelklef wouldn't that just be a specialized form of threading macro?

(defmacro ->! [lval &rest forms]
  `(setv ~lval
         (-> ~lval ~@forms)))

;; eg.
(setv x 1)

(->! x
  (str)
  (repeat 5)
  (zip (range 10))
  (list))

(print x)
;; => [('1', 0), ('1', 1), ('1', 2), ('1', 3), ('1', 4)]
Quelklef commented 5 years ago

Yeah. But I've been pondering this kind of macro for a while and I think it may be useful enough to warrant its own thing.

Quelklef commented 5 years ago

I suppose it doesn't make sense to call (-!> x succ) a "solution" to this discussion since it's more verbose than (+= x 1) and really the power of mutative inc/dec is concision. Written-out increment and decrement functions are off the board as well.

My personal vote goes for:

  1. There are no functions named inc/dec.
  2. Mutative increment/decrement is done with += and -=.
  3. Non-mutative increment/decrement is called succ/pred.

This would also fit better with Python's "one way to do it" mantra.

gilch commented 5 years ago

My vote would be for inc/dec non-mutative like Clojure (status quo). I understand that immutability is not as pervasive in Hy as it is in Clojure, so failing that, we should fall back on the names 1+/1- like Common Lisp for non-mutative instead of succ/pred. Generally we should borrow from Python, Clojure, Common Lisp, in that order.

Quelklef commented 5 years ago

I get that Hy follows Clojure, but I would opine that Clojure's naming is a mistake. I presume that inc and dec stand for increment and decrement. To "increment" and to "decrement" are both fundamentally mutative operations, and having them pure seems misleading.

And by status quo more general than just Clojure, inc and dec should be succ and pred.

asemic-horizon commented 4 years ago

I'm not sure I should get a vote, but I can't help being opinionated here.

1) I know Hy is supposed to be a moving target at this stage, but breaking changes should be minimized. I'm sure there are excellent reasons for having dropped let, for example, but the fallout is a good chunk of the small amount of Hy code there is around being broken.

2) Python is fairly confusing around what's in-place and what's a proper function (i.e. the behavior of sort versus sorted). With the full character set and so many traditions to choose from, Hy can do the big-tent thing by supporting a pure inc, a mutating incf (and an inc!) and succ as a synonym for numeric types. In my mind inc and succ are already slightly different concepts (cardinal vs ordinal numbers).

3) There are probably good reasons not to do (2) to the extreme (elegance, for one; it matters), but I'd argue the default policy in discussions like this should be "do the big-tent thing" (at the cost of proliferating synonyms) and then the argument for choosing One True Option be made. Most often this would lead to the One True Option anyway, but it'd simplify discussions and minimizing the risk of unnecessary breaking changes (even if at times these are going to be necessary anyway).