proj-oot-ootSyntaxNotes5

J is another language that has _3 instead of -3 (and % for division instead of /)

arg, mb we should just do that

---

J has a syntax rule that floating point literals can't start with a '.' eg it's '0.5', not '.5'

---

In J,

_5e_3

is 0.005

---

in J, '=.' is used for fn defn, instead of the ':=' that we have. I like '=.' better, because it's easier to type, because '.' is unshifted whereas ':' is shifted; otoh fn definition will be relatively uncommon and we may want to save the '.' for something even more common. Otoh even if '.' has another meaning, that other meaning probably won't work with '=', so '=.' (or even '.=') is probably still open.

so think about changing this.

---

(re-)reading the J primer, i have mixed feelings about some syntax things.

I recall when i first learned about languages that used _3 for -3, i thought that was an abomination that made the language harder to learn for no good reason (slight syntactic regularity and easierness for the compiler writer was not a good reason). But now i feel the other way; simplicity is paramount, and one more new convention to remember is worth it not to have the syntactic wart of - being the one operator with special unary parsing. However, the solution i came to in Oot went the other way, generalizing the special case of unary negation (eg -3) to everything; i threw out the principle that it doesn't matter if you put whitespace in between operators and their arguments, so "a + b", "a +b", "a+ b" (infix, prefix, suffix usage of '+') can now mean 3 totally different things ("a+b" would mean the same as "(a+b)").

Now upon (re)reading the J primer, i feel that J's principle of 'ambivalence', which states that operators have different meanings as a "monad" and "dyad" (eg the + in "a + b" mean 'addition', but "+ a" means 'complex conjugate'), is bad. The J Primer claims that often the monad and dyad meanings of a 'verb' are related, however eg the relationship between addition and complex conjugate is imo sufficiently tenuous that you could easily remember one and forget the other. Eg 'Complex conjugate' is just an ordinary arithmetical operation, not some special language-level primitive or something with syntax or some metaprogrammy thing; it doesn't warrant the additional memorization/confusion to be stuck together with '+'.

But J here is being LESS confusing that i am proposing for Oot; in my proposal, each symbol can have not 2 but THREE totally different meanings.

Can we justify this? mb:

---

if '.' has a prefix meaning, then that's confusing with floating-point literals, eg is .5 .-prefix applied to literal '5', or 0.5?

J prohibits (or used to prohibit) floating point literals starting with . (so .5 is illegal, 0.5 is not); mb we should do that, and then ALSO prohibit .5 meaning .-prefix (5); .5 would just be prohibited in any case to reduce confusing, and you would use either '0.5' or '.(5)'.

---

someone's opinion of J:

"Amazing programming language but if you don't use it for a couple of weeks, you just forget it all. It's so terse. But great fun " [1]

seems to validate my concerns about ambivalence making things hard to remember.

---

J has right associativity ('verbs', that is functions/ordinary operators, have no special precedence levels). [2] claims this is because of some of the fancy things they do.

---

J has 'name' definition (variable assignment), but also 'verb define'. The syntax for 'verb define' is rather confusing; (a) it's different from variable assignment, (b) '3 : 0' means a define of type 3 (verb, monadic), and 0 means the actual definition is found on the following lines, (c) the definition is terminated by an unmatched ).

The argument to the verb is implicitly 'x' and 'y' for dyadic (infix binary) verbs, and 'y' for monadic (unary) verbs (y because the argument for an unary verb is on its right)

[3]

instead of ': 0' you can have : 'body'

where 'body' is the body of the function defn, enclosed in a string!

---

in haskell, function application is left associative:

f a b == ((f a) b)

in Haskell, function application has precedence over operators, so

f a b + g d e = (f a b) + (g d e)

in Haskell, operators can be rephrased as functions, so:

map foo $ xs
== $ (map foo) (xs)
== ((map foo) xs)

---

afaict J doesnt syntactically distinguish between lists of length 1 and scalars, and it has operations on lists automatically be elementwise when they are the same length, and scalar when one list is of length 1.

Eg:

   2 4 6 * 7 8 914 32 54 2 * 2 3 4 4 6 8
   2 3 4 = 7 3 80 1 0 2 < 0 1 2 3 4 5 0 0 0 1 1 1

(examples from [4] )

that's too magic for me, but i do want to emphasize that these things shouldnt be any harder than that; we need some syntactic sugar so that you aren't typing eg 'map' all over the place to do simple things like this

---

" Forks are defined as follows: (f g h) y ←→ (f y) g (h y) x (f g h) y ←→ (x f y) g (x h y)

Moreover, (f g p q r) ←→ (f g (p q r)). "

"any sentence involving one or two arguments that did not use its arguments as an operand, can be written tacitly with fork, compose, the left and right identity functions, and constant functions."

[5]

---

example of J being concise:

   # $ 2 3 $ 'a'	NB. table has rank 2
2

dyadic (binary infix fn) '$' is 'reshape' (as in Matlab). monadic (unary prefix fn) '$' is 'shape' (as in Matlab). The left '$' is unary because to its left is an operator ('verb'), which i guess cannot be a dyadic argument (i think). # is 'len' (as in Python). J is right-associative. 'NB.' is comment-to-EOL. So we have:

  1. $ 2 3 $ 'a'

(# ($ (2 3 $ 'a')))

(# ($ (['a' 'a' 'a' ; 'a' 'a' 'a']))

(# (2 3)

2

It's like if we had right-associative:

len shape reshape(2 3, 'a')

Notice how the right-associativity, combined with the monadic/dyadic overloading (overloading lets fn names be really short because we can reuse each single character name twice), combined with resolving the monadic/dyadic overloading by whether there is another operator ('verb') left-adjacent to the operator in question, leads to conciseness.

---

(after reading about rank conjunctions)

so perhaps the magic of J's conciseness is:

---

J vs Python's numpy:

" snapster24

I don't think numpy explicitly calls it 'rank', but the central object in numpy is the n-dimensional array. Operators and functions can be applied to arrays, like in J, and operators can operate on two arrays of different dimensionality (rank), and the manner in which this is done in numpy is called 'broadcasting'. For example, if A is a 1-dimensional array of length N, and B is a 2-dimensional array of size NxN?, then you can add A to each 'row' of B with:

A+B # alternatively A[newaxis, :] + B

and you can add A to each 'column' of B with:

A + B 2

Godspiral

sounds a bit more like restructuring, but still neat.

A + B in J,

or to add A to each row of B,

A +"1 B 1

davmash

J actually influenced numpy and a lot of the methods are very similar (even some names like ravel). As others have pointed out, a major difference is around rank; J uses verb rank where numpy uses broadcasting rules and the "axis=" pattern to achieve similar things. One interesting thing to note is that numpy only supports array shapes up to 32 dimensions while J can blow past that essentially until you run out of memory. On the other hand, numpy has support for no-copy views which can be a huge boon to large data/ limited-memory situations. Also, for better or worse numpy programming involves much more concern about explicit datatypes and memory layouts -- I'm not sure how or if J handles these kind of things. "

[6]

---

https://news.ycombinator.com/item?id=9708038

" Can you suggest a simple program for which idiomatic J differs significantly from idiomatic python/numpy? As I said, I've been unable to come up with one, or find one in aforementioned paper. " two answers are given (not reproduced here)

---

seeing how nicely right-assoc works out for J suggests that we really want a 'right-assoc pipe' operator (like Haskell '$') that is unshifted; mb '' instead of

also, i like my commas-as-auto-parens idea. Dunno what to do about multiple return args, though; special case for single comma (',')?

oh yeah, weren't we going to use commas as 'right-assoc pipe' too?

eg

g , f x

that's real easy to type...

---

if unary - is negation and negation of a function is inverse, how to distinguish -f from "arithmetic negation composed with f" from "inverse of f"? so mb unary - is just arithmetic negation..

---

an example of J's monad/dyad overloading being lame is found on [7], where it points out that '/+' can be either 'sum' or 'outer product of +' depending on whether it is used monadically or dyadically

i guess i think the monad/dyad overloading is too much overloading here.

especially since two things of different arity are being overloaded. It's neat that this can be resolved using syntactic constraints such as that a verb cant take a verb as an argument, but this is still additional complexity. although perhaps just the memorization of which functions goes with which symbols is more important than the syntactic complexity.

---

here's a direct comparison of Channel stuff between Golang and the Ruby-like Crystal lang:

" Speaking of ping-pong, you have this snippet from the “Go by Example” site:

package main import "fmt"

func ping(pings chan<- string, msg string) { pings <- msg }

func pong(pings <-chan string, pongs chan<- string) { msg := <-pings pongs <- msg }

func main() { pings := make(chan string, 1) pongs := make(chan string, 1) ping(pings, "passed message") pong(pings, pongs) fmt.Println(<-pongs) }

And the Crystal version:

def ping(pings, message) pings.send message end

def pong(pings, pongs) message = pings.receive pongs.send message end

pings = Channel(String).new pongs = Channel(String).new spawn ping pings, "passed message" spawn pong pings, pongs puts pongs.receive # => "passed message" "

-- https://blog.codeship.com/an-introduction-to-crystal-fast-as-c-slick-as-ruby/

some notes:

---

Apparently Nim also does the thing i am considering wherein 2+2 == (2 + 2), and this guy seems not to like it:

https://news.ycombinator.com/item?id=12225440

---

in the COLA Pepsi language [8], comments are contained within double quotes:

    "this is ignored"

reminds me of Python docstrings.

In Python, i guess the distinction is that docstrings are accessible from within the program, while actual comments are stripped out during compilation?

---

_ could be NIL and * could be ALL

---

Rust's 'attribute' syntax ('#' is for attributes):

  1. attr_name
  2. attr_var=value_literal
  3. attr_name(attr_arg1, attr_arg2, ...)
  4. means 'attribute applies to the item that follows the attribute'
  5. ! means 'attribute applies to the item within which the attribute is declared'

in their words:

" An attribute is a general, free-form metadatum that is interpreted according to name, convention, and language and compiler version. Attributes may appear as any of:

    A single identifier, the attribute name
    An identifier followed by the equals sign '=' and a literal, providing a key/value pair
    An identifier followed by a parenthesized list of sub-attribute arguments

Attributes with a bang ("!") after the hash ("#") apply to the item that the attribute is declared within. Attributes that do not have a bang after the hash apply to the item that follows the attribute. "

---

smalltalk vs haskell syntax:

in Smalltalk, "Unary messages are executed first, then binary messages and finally keyword messages" and "Between messages of similar precedence, expressions are executed from left to right" so:

2 raisedTo: 3 + 2. == 2 raisedTo: (3 + 2).

and

-3 abs negated reciprocal. == ((-3 abs) negated) reciprocal.

compare to Haskell:

like Smalltalk, a b c == (a b) c, but the meaning here is reversed because in Smalltalk, the functions are b and c, not a.

in Smalltalk, the keyword messages are loosest binding, the opposite of tightest-binding function application in Haskell.

---

for anonymous autoarguments, scope ends when an inner block starts:

map({_1*2}, _1) # two different '_1's

{}s are unevaluated/suspended/non-strict

---

" Quite often we need to declare data structures in our code. Common examples include declaring a list or map. In Java and C# these simple tasks include mostly noise which makes for very ugly, verbose declarative programming. For this reason, you often find the declarative parts of a Java or C# application shoved off into XML files.

Fantom incorporates declarative programming right into the language. Fantom supports a literal syntax for lists, maps, ranges, uris, and durations. Fantom also includes a text serialization syntax which is human readable and writable. The serialization syntax is a clean subset of the programming language - so you can paste a serialization file right into your source code as an expression. "

" Field Accessors: field accessors are defined implicitly - another area where idiomatic Java code has a low signal to noise ratio "

---

this is crazy:

"Notice also that the function being defined is ((U+00B7))add. Go symbols end up in the resulting objects using their fully-qualified names, e.g. github.com/nelhage/gojit.Alloc. However, since / and . are punctuation character in the C and assembly syntax, they’ve extended the tools to accept U+00B7 MIDDLE DOT and U+2215 DIVISION SLASH in the input, which get converted to “normal” dots and slashes, as Russ Cox explains on the mailing list."

---

in haskell syntax, you don't need to put () after a function to call it, and to use () do distinguish first-class functions being passed from functions being called, b/c function application (by juxtaposition) does this (eg in "map f list", f is just a function, in "f x y" f is being applied; in other languages the former would have "map(f, list)" and the latter "f(x,y)"); otoh, there are no 0-ary functions (suspensions)

---

mb use haskell-ish syntax but use an 'address-of' operator to create suspensions? eg "f0 = &f" is 0-ary f; to deref do "*f0". So "f2 = &f; f2 x y" doesn't work, but "f2 = &f; *f2 x y" does. Maybe also require that our lenient evaluation never goes past a "*" until needed (lazy). This would ensure that with "map *f2 list", if f2 has side-effects, those side effects are never activated until needed.

However, this is in conflict with:

---

mb tuple syntax with mandatory parens: (a,b,c); would that help with our desire to use commas to group, but also for multiple return values, but also for tuples? Probably not...

---

in Python, identifiers with a double underscore have their name managled to insert the classname, eg __example becomes __Foo_example (assuming it is defined in the Foo class). This is supposed to help with not having to worry about name conflicts when subclassing. Good idea; we should do something like it for our 'private' variables.

---

comparing python to ruby:

sum([p.price for p in products if p.type == "x"])

products.select {

productproduct.type == 'x' }.map(&:price).reduce(:+)

K0nserv 4 days ago [-]

I guess it's a personal style choice, the Python code is more performant(less iterations over the data set), but I like the ruby version better.

reply

ezrast 3 days ago [-]

It's only one iteration if you throw a .lazy in there:

products.lazy.select {

productproduct.type == 'x' }.map(&:price).reduce(:+)

reply

---

replacement idea for curly braces:

    if condition:
      statement
      statement.

---

" an optional argument at the caller side (and because the feature doesn’t exist, I’m having to invent syntax to show what I mean):

(define (run-callback callback) (callback mandatory-value [#:foo 234]))

(run-callback (lambda (mandatory-arg) ...)) ;; ignores the extra value (run-callback (lambda (mandatory-arg #:foo [foo 123]) ...)) ;; uses it

The intent here is that the procedure is permitted not to care (or even to know) about the additional value its caller supplies.

This would be useful for callbacks and other situations where the code invoking a procedure has potentially-useful information that the specific (and statically-unknown) procedure being called may or may not care about. " -- http://www.eighty-twenty.org/2012/08/01/racket-optional-arguments

(i guess a Python function taking kw would satisfy this, and we'll have something similar in Oot)

---

are Rust 'traits' like typeclasses/interfaces? if so, 'trait' is shorter to type, so mb switch to that terminology

---

draegtun 1 day ago [-]

Barely touch regexes these days because for last few years I've been using Rebol / Red parse more and more.

Here's a translation of the first SRL example in the parse dialect:

  [
      some [number | letter | symbol]                 
      "@"
      some [number | letter | "-" ]                   
      some ["." copy tld some [number | letter | "-" ]]
      if (parse tld [letter some letter])
  ]

And here's a full matching example:

  number: charset "0123456789"
  letter: charset [#"a" - #"z"]
  symbol: charset "._%+-"
  
  s: {Message me at you@example.com. Business email: business@awesome.email}
  
  parse s [ 
    any [
        copy local some [number | letter | symbol]
        "@" 
        copy domain [
            some [number | letter | "-" ] 
            some ["." copy tld some [number | letter | "-" ]]
        ]   
        if (parse tld [letter some letter])
        (print ["local:" local "domain:" domain])
skip
    ]   
  ]

Some parse links:

reply

QuantumAphid? 1 day ago [-]

Same for me. About a decade ago I started using Rebol for shell-scripts, file management and working with web API's. It's nice to work with a syntax where I can look at an older parse routine and figure out what I was trying to do just by reading it. Only time I use regex is within my code editor.

reply

GordonS? 1 day ago [-]

I don't mind regular expressions myself, but this does look quite nice. Any idea if this has been implemented for anything other than Rebol (which I'd never heard of)?

reply

rgchris 1 day ago [-]

There was a Parse-inspired project for JavaScript?, but I'm not sure to what extent it was developed. There was also a Parse implementation in Topaz[1] (which itself is implemented in JavaScript?) but is as of now unfinished.

It'd be difficult to implement as tightly in another language that doesn't have Rebol's (or a somewhat Lisp-like) free-form code-is-data/data-is-code[2] approach. Rebol and its Parse dialect share the same vocabulary and block structure that amongst other things: makes it easy to insert progress-dependent Rebol snippets within Parse; build Parse blocks dynamically (mid-Parse if needed!); build Rebol code from parsed data; develop complex grammar rules very similar to EBNF[3]. The article linked above[4] (and now linked again below :) does a good job of fleshing out these ideas and why it may remain a unique feature for some time.

[1]: http://reb4.me/tt

[2]: http://rebol.info/rebolsteps.html

[3]: http://codereview.stackexchange.com/q/87716/46291

[4]: http://blog.hostilefork.com/why-rebol-red-parse-cool/

reply

---

" defining new records in Haskell is extremely cheap compared to other languages and each field can be a distinct type:

data MyRecord? = MyRecord? { foo :: String , bar :: Int , baz :: Double }

myRecord = MyRecord? { foo = "Hello" , bar = 1 , baz = 2.0 } "

---

one confusing thing about Haskell's syntax:

in type signatures with contexts, eg:

add :: Num n => n -> n -> n

within the context part (to the left of the =>), juxtaposition (Typeclass typevariable) means 'predicate Typeclass is true of typevariable'. But everywhere else in Haskell, juxtaposition means function calling. This makes sense if you think of Typeclass as a predicate function, and the point of 'Num n =>' as an assertion that 'Num n' evaluates to True. But that's somewhat surprising.

(this is NOT the sort of thing that i think is a big deal for a language though; a 'moderately experienced' user of the language will have memorized this and not forgotten it, so no problem)

---

thinkpad20 188 days ago

parent [-]on: Oden: experimental, statically-typed functional la...

I'm a bit disappointed by the double colon; it's my least favorite part of Haskell syntax (I probably shouldn't care, but there you go). It also bugs me in PureScript?. However, Agda, Idris, and Elm, all of which have syntax heavily inspired by Haskell, all do it the "right way", so there's no reason a Haskell-inspired language can't. Plus, this doesn't look that much like Haskell, certainly not to the point of being derivative.

---

remember that we need an operator to mean 'autocoerce', like Haskell's 'fromX' and 'toX'. How about tilde '~'? Eg instead of "print str(3)" we would have "print ~3".

this may conflict with tilde as a prefix for special literals, though. Maybe one of them (probably the literal one?) can be postfix. autocoerce is essentially an infix operator; it only makes sense between one thing and something else (in the above example, between the print and the 3), so prefix makes more sense for that.

or mb we should use '`' for this. ` is easier to type on US keyboards, maybe not other international ones though?

---

or mb we should reserve backquote for its use in Lisp (antiquote)

---

<: for subclass-of

---

we should probably let %% be in/elem/member, and let % be division

---

control structures:

consider:

you don't want to have to put () or {} around the loop condition, even though in reality the loop condition is in a block which is passed as an argument to 'while'. Can we have some syntax for this?

Isn't this the sort of place where we wanted to use our '' 'kelp' syntax, eg:

ife i > 0: {dosomething} {dosomethingelse}

but, ':' is now being used for type annotations, and '::' is now being used for namespaces.

What we seem to want is something like the ',,' autoseparator, but for blocks instead of parens.

mb

ife i > 0 {dosomething} {dosomethingelse}

or

ife i > 0 / {dosomething} {dosomethingelse}

Let's think about this. I bet it'll turn out to be:

ife i > 0 {dosomething} {dosomethingelse}

---

'&' for AND and '

' for OR deserve syntax; because these are understood by the verifier in assertions (and possibly in other logical stuff; eg microkanren has conjunctions and disjunctions)

---

in Oot Assembly, we see:

This suggests that maybe we should have pass-by-reference. We can unify the syntax for this with our 'mutable' syntax:

---

http://denis.papathanasiou.org/posts/2015.12.26.post.html (i already read it, no need to reread) provides a nice comparison of a small Golang program to its corresponding C program, showing how the C program is more verbose. I think difference is not really much due to syntax, but i don't know where else to put that link so i put it here.

---

we need an 'extension sigil' for ppl who are extending the type system and need some easy-to-type sigils. Eg if the extension sigil were $, then you'd have things like $-, $@, $*, which would be different user-defined sigils, in the same way that libraries can define punctuation for infix operators

---

a (persuasive, to me) argument that (who, capnproto?) made for having the type of a variable AFTER the var itself in decls: b/c then the varname is on the left-hand column, which makes it easier for a human to scan while reading the code

---

need a fast way to do: print("hi", file=sys.stderr)

---

boilerplate in Python:

    def __init__(self, PC=0, stack_depth=0, labels=None):
        self.PC = PC
        self.stack_depth = stack_depth
        if labels is None:
           labels = {}
        self.labels = labels
    def __repr__(self):
        return "PC={}; stack_depth={}; labels={}".format(self.PC, self.stack_depth, self.labels)
    def __eq__(self, other):
        return (self.PC == other.PC) and (self.stack_depth == other.stack_depth) and (self.labels == other.labels)

---

y'know, "while () {}" is already fine; it will be parsed as giving two arguments to 'while', which is what we want.

---

JS Flow uses a '?' sigil prefix in type annotations to 'option-ify' a type. Eg '?string' is like 'Maybe String'.

---

killercup 3 hours ago

parent flag favorite on: 2017 Rust Roadmap

Not in the type system itself, but you could write a lint to forbid heap allocation. This way, you could annotate a function (with e.g. `#[forbid(allocations)]`) to get a compile error when your function (or code your function calls) tries to allocate. This might not be easy, though :)

---

"The precedence level of NOT (the ! operator) is very high in C. This is almost never desired, so you end up needing parentheses most times you want to use the ! operator. " -- http://www.toves.org/books/cpy/

" C defines assignment as an operator, whereas Python defines assignment as a statement. The value of the assignment operator is the value assigned. A consequence of C's design is that an assignment can legally be part of another statement.

    while ((a = getchar()) != EOF)

Here, we assign the value returned by getchar() to the variable a, and then we test whether the value assigned to a matches the EOF constant, which is used to decide whether to repeat the loop again. Many people contend that this style of programming is extraordinarily bad style; others find it too convenient to avoid. Python, of course, was designed so that an assignment must occur as its own separate statement, so nesting assignments within a while statement's condition is illegal in Python.

C's operators ++ and -- are for incrementing and decrementing a variable. Thus, the statement “i++” is a shorter form of the statement “i = i + 1” (or "i += 1”)." " -- http://www.toves.org/books/cpy/

---

" async def proxy(dest_host, dest_port, main_task, source_sock, addr): await main_task.cancel() dest_sock = await curio.open_connection(dest_host, dest_port) async with dest_sock: await copy_all(source_sock, dest_sock)

Are you kidding me? Simplified that is

  async def func():
    await f()
    dest_sock = await f()
    async with dest_sock:
      await f()

Every other token is async or await. No thank you.

reply "

---

on python vs octave vs R vs Julia syntax for matrix stuff:

sampo 1 day ago [-]

In the Stanford/Coursera machine learning class, Andrew Ng said that his teaching experience is that students pick up octave/matlab quicker and the course can cover more actual machine learning, compared to python where more time is spent learning the language. ...

Say, you have some numbers for a matrix and a vector in files and want to read them in and multiple the vector by the matrix.

In octave you are done in 3 lines of code in 30 seconds.

In python, you first figure which modules to import, the difference between python arrays and numpy arrays, and god forbid you happen to find the numpy matrix type instead of numpy array type. After 5 minutes you think you're all set to calculate the M * v, but then your vector happens to be a line vector and not a column vector and you need to learn the difference. Also it's nicer to write M * v than np.dot(M,v).

...

reply

sampo 23 hours ago [-]

Just to illustrate:

Octave:

    m = [0 1 0; 0 0 1; 1 0 0]
    v = [2 3 1]'
    m\v
    
    ans =
    
       1
       2
       3

Python:

    import numpy as np
    m = np.array([[0,1,0],[0,0,1],[1,0,0]])
    v = np.transpose(np.array([2,3,1]))
    # wtf? oh, I guess then
    v = np.transpose(np.array([[2,3,1]]))
    np.linalg.solve(m,v)
    
    array([[ 1.],
           [ 2.],
           [ 3.]])

... Edit: a reply below makes a good point simplifying the Python code a little bit.

reply

messe 23 hours ago [-]

What's wrong with:

    >>> import numpy as np
    >>> m = np.array([[0,1,0],[0,0,1],[1,0,0]])
    >>> v = np.array([2,3,1])
    >>> np.linalg.solve(m,v)
    array([ 1.,  2.,  3.])

No need to transpose, as numpy handles row and column vectors identically. Using the above variables `m` and `v`:

    >>> v @ m   # treated as row vector
    array([1, 2, 3])
    >>> m @ v   # treated as column vector
    array([3, 1, 2])

Where `@`, for those who don't know, is the matrix multiplication operator (`np.dot`) introduced in recent versions of python 3.

reply

TheSpiceIsLife? 11 hours ago [-]

...

In the Stanford/Coursera machine learning class, Andrew Ng said that his teaching experience is that students pick up octave/matlab quicker and the course can cover more actual machine learning, compared to python where more time is spent learning the language.

Then "which version of Python, and how is that different..." etc.

reply

tombone12 23 hours ago [-]

Why not just: v = np.array([2,3,1]).T

... reply

sampo 23 hours ago [-]

You are right, T would be nicer than np.tranpose. But the first google hit on 'numpy transpose' [1] doesn't give that as as example.

Also you too made the same mistake: np.array([2,3,1]).T doesn't do anything, you need np.array([[2,3,1?]]).T

[1] https://docs.scipy.org/doc/numpy/reference/generated/numpy.t...

reply

brudgers 23 hours ago [-]

I think that's kindasorta of reason for Ng's preference: students will focus on the subject of machine learning and not spend time on the ins and outs of Python and Numpy (or these days TensorFlow?). It's the same sort of pedagogical approach that keeps SML as an active teaching language.

When someone googles Matlab/Octave there won't be the same mixture of contexts as there is for Python. With Python there's "2 or 3?" before even starting. Than Cython or Jython or PyPy?? That's nothing against Python except that in one particular time limited context, the questions are a distraction {without even considering the complaints of students when the choice of Python implementation is contrary to their opinion}.

reply

em500 22 hours ago [-]

R:

    m = matrix( c(0,0,1,1,0,0,0,1,0), nrow=3 )
    v = c(2,3,1)
    solve(m,v)
    [1] 1 2 3

Julia: for this code snippet the syntax is identical to Matlab:

    m = [0 1 0; 0 0 1; 1 0 0]
    v = [2 3 1]'
    m\v
    3×1 Array{Float64,2}:
    1.0
    2.0
    3.0

reply

hasch 20 hours ago [-]

here is sagemath

    m = matrix([[0, 1, 0],
                [0, 0, 1],
                [1, 0, 0]])
    v = vector([2, 3, 1])
    m \ v

(1, 2, 3)

and then

    sol = m \ v
    m * sol

(2, 3, 1)

reply

bunderbunder 1 day ago [-]

...

Getting comfortable with Octave for doing basic vector/matrix operations took very little time, and within an hour I was able to just focus on learning the math. By contrast, I've been using Numpy on-and-off for a year now, and I still feel wedded to the reference manual.

Keeping track of all the @$@#% types is definitely a chore. There may be technical advantages to doing things that way, but that doesn't make it any more learner-friendly. Nor does the Python community's habit of not bothering to specify types in the documentation help things in that department.

reply

Steeeve 1 day ago [-]

I'm with you. When you are doing things as your day-to-day learning the syntax and gotchas associated with whatever language are pretty easy, but when you come at it every once in a while working with Octave or Matlab are so much easier. ...

rz2k 1 day ago [-]

I took the EdX?/MIT course[1] on optimization methods and constraint solvers using Julia and JuMP? and it was really fun.

Julia wasn't around, or it was very early, when he designed the Machine Learning course or was teaching Stanford students, and he's moved on since then. I wonder if he would likely choose Julia now.

I like R, but understand that %*% for matrix multiplication, solve() instead of \, and the relatively cumbersome syntax for defining matrices indicate that it not designed primarily for users to interact with matrices at a lower, mechanical level. The xapply() functions can also be more confusing than picturing how you iterate through loops. Python too can be verbose for doing the simple/toy problems that are helpful when learning.

Julia however comes with the easy Matlab/Octave syntax for handling matrices. But then there is a lot of of syntactic sugar too after you get past the early stages. Even things like the built-in support for intermixing Greek letters were surprisingly helpful.

...

[1] https://www.edx.org/course/optimization-methods-business-ana...!

reply

Animats 22 hours ago [-]

Matlab and Octave have multidimensional arrays built in. Few modern languages do. C, C++, Python, Go, Rust - no built-in multidimensional arrays. (Arrays of arrays are not the same thing.) There are lots of array packages, but they often don't talk to each other. Classic Python gotcha: "+" for Python arrays is concatenation, but for NumPy? arrays, it's elementwise add. Mixed-mode semantics are complicated.

...

Animats 19 hours ago [-]

There are performance, and in some languages, safety issues with arrays of arrays. Arrays of arrays can be ragged - not all the rows need be the same length. Languages which do subscript checking have to deal with this, and usually can't hoist subscript checks out of inner loops.

Allocating an array of arrays can require a lot of allocations, as does copying such an array. This gets expensive if you have some language where arrays are first-class result types. You can't just do one allocate, then copy the entire array.

The C idiom "a[i][j]" has become pervasive, replacing actual multidimensional array subscripts such as "a[i,j]" (Pascal, Modula) or "a(i,j)" (Octave, MATLAB and FORTRAN). Amusingly, you can't overload "operator[]" in C++ with more than one argument. It's a syntax problem. The comma operator (the "evaluate but ignore first operand, return second operand" operator) has higher precedence inside "a[]" than inside "a()". This is a legacy from C's use of the comma operator inside macros.

reply

---

a Rust syntax example from https://ruudvanasseldonk.com/2016/11/30/zero-cost-abstractions :

for i in 12..buffer.len() { let prediction = coefficients.iter() .zip(&buffer[i - 12..i]) .map(

(&c, &s)c * s as i64)
                                 .sum::<i64>() >> qlp_shift;
    let delta = buffer[i];
    buffer[i] = prediction as i32 + delta;}

some notes:

xfn) for lambda fns

---

so, just to remind myself for the 100th time, some possibilities for capitalization and uppercase:

---

Python new string interpolation:

>>> name = "Fred" >>> f"He said his name is {name}." 'He said his name is Fred.' >>> width = 10 >>> precision = 4 >>> value = decimal.Decimal("12.34567") >>> f"result: {value:{width}.{precision}}" # nested fields 'result: 12.35'

kazagistar 2 days ago [-]

I'm disappointed in the interpolated strings. We finally get them, but its already behind the curve compared to Scala or C#, due to not being lazy and allowing context sensitive string interpolation.

The better design binds the values to the string, but does not interpolate into a string type fully. Then, the resulting object can be passed to a consumer like an SQL engine (and appropriately escaped) or an internationalization library (and swapped out for a translated string before interpolation).

I mean, I appreciate what they did, but it seems like missing a massive opportunity to provide a linguistic building block for library authors.

reply

me: i think this should be our default (use 'r' to disable, not 'f' to enable), and we should do as kazagistar suggests and bind "the values to the string, but does not interpolate into a string type fully. Then, the resulting object can be passed to a consumer like an SQL engine (and appropriately escaped) or an internationalization library (and swapped out for a translated string before interpolation)."

---

on Pyret's allowance of hyphens within identifiers:

danso 14 hours ago [-]

Example from the OP:

        fun to-celsius(f):
          (f - 32) * (5 / 9)
        end

What's the justification for allowing the use of hyphens/dashes in reference names, when underscores would seemingly provide the same purpose? One of the most common problems I notice in newbie code is inconsistency in using whitespace, e.g. `a-b` vs `a - b`, though in that situation, for Python and virtually every other language I've used, those both result in subtracting b from a. But in Pyret, it seems that `a-b` would be interpreted as a reference? That seems needlessly confusing for no benefit in readability over using snakecase.

Beginners frequently have issues with grammar, that is, they are pretty much unaware of it when trying to figure out the many other things they have to learn about programming. Even in SQL, I forget that it must be quite confusing for beginners to parse out the meaning of the `` in something as simple as:

     SELECT mytable.*, (a * b) AS myproduct, 
          COUNT(*) AS the count
     FROM mytable ...

Doesn't seem worth it to make the hyphen, which is so frequently associated with subtraction and negative numbers, have just a decorative meaning when used between word tokens (as opposed to subtraction of values represented by variables).

reply

jswrenn 14 hours ago [-]

Pyret inherits hyphens-in-identifiers from Scheme/Racket. One of Pyret's largest users, Bootstrap [1], has long-used a dialect of Scheme, and has recently introduced a curriculum that uses Pyret. For these users, "virtually every other language" allows for hyphens in identifiers.

Scheme mitigates the spacing issue with s-expressions. Pyret attempts to mitigate it by enforcing that operators should be separated from their operand with at least one space.

(Disclosure: I am an occasional developer of Pyret.)

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

reply

eridius 13 hours ago [-]

Scheme and Racket are both LISPs, with very different syntax. Hyphens in identifiers aren't a hazard, because binary operators don't go between two other identifiers, and operators must be separated with spaces, e.g. subtraction looks like `(- 2 1)` instead of `2 - 1`. This means that using hyphens in identifiers is quite safe.

But Pyret is using more traditional syntax, where binary operators go between their operands, e.g. `2 - 1`, which means using hyphens in identifiers is a hazard as the parent comment describes.

reply

simplify 12 hours ago [-]

The problem is overblown. It's not going to cause any deep, hard-to-debug errors. If you accidentally type `a-b`, you'll get an error message that says "a-b is not defined". Fix it and you're done.

reply

samcal 12 hours ago [-]

While I agree that the problem is not a very big deal, I think that you might be surprised how difficult understanding compiler errors can be for newcomers.

reply

skrishnamurthi 11 hours ago [-]

The Pyret design team has done perhaps the most in-depth research into error messages of anyone [e.g.: http://cs.brown.edu/~sk/Publications/Papers/Published/mfk-me..., http://cs.brown.edu/~sk/Publications/Papers/Published/mfk-mi...]. We're deeply aware of the effect of error messages. This isn't a problem.

reply

---

sigil for custom syntax like "3 #as float" or "#mutable var1" (#mut) (or, were we using capitalization for that?)

---

list of syntax relating to function pointer declarations in C:

http://goshdarnfunctionpointers.com/ https://news.ycombinator.com/item?id=13437182

---