Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
FizzBuzz in J, Explained (wycd.net)
103 points by wyc on Jan 19, 2017 | hide | past | favorite | 51 comments


Paraphrasing an earlier Reddit post, here's how it might look in K3.

Generate a range of numbers up to 20 (for brevity), inclusive:

      1+!20
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Apply a function ({x!/:3 5}), which takes an element modulo 3 and 5, to the range:

      {x!/:3 5}1+!20
    (1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2
     1 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0)
Taking the negation (~) shows us the places the elements divide evenly:

      {~x!/:3 5}1+!20
    (0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0
     0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1)
Convert these into base-2 indices:

      {2 _sv~x!/:3 5}1+!20
    0 0 2 0 1 2 0 0 2 1 0 2 0 0 3 0 0 2 0 1
We can then use those indices to select from a list. Note the addition of a map ('), because if we continue performing all these operations in parallel we won't have access to x as some particular item of the list:

      {(x;"Buzz";"Fizz";"FizzBuzz")2 _sv~x!/:3 5}'1+!20
    (1;2;"Fizz";4;"Buzz";"Fizz";7;8;"Fizz";"Buzz";11;"Fizz";13;14;"FizzBuzz";16;17;"Fizz";19;"Buzz")


Nice, clever use of base change.

What about something like

    n{:[~#y;$x;y]}'{,/("Fizz";"Buzz")@&~x!/:3 5}'n:1+!20
to avoid duplicating the string combinations? The conditional is unfortunate, would like to get rid of it. But should be straightforward to extend if we want to introduce further string combinations for numbers divisible by, e.g., 7. Though anticipating such things goes against the spirit of k I suppose. :-)


To translate that as literally as possible into Dyalog

  fizzbuzz ← {
    {(⍵ 'buzz' 'fizz' 'fizzbuzz')[1+2⊥0=3 5∘.|⍵]}¨⍵
  }
called as

  fizzbuzz ⍳100
or just

  {(⍵ 'buzz' 'fizz' 'fizzbuzz')[1+2⊥0=3 5∘.|⍵]}¨⍳100
with unnecessary parens

  {(⍵ 'buzz' 'fizz' 'fizzbuzz')[1+(2⊥(0=((3 5)∘.|⍵)))]}¨⍳100


Since you are using ¨, ⍵ is a scalar, so you don't need the ∘.

Translated back to J

  ((;'Buzz';'Fizz';'FizzBuzz'"_){~2#.0=3 5|])"0>:i.100
The boxed list in J feels a bit cumbersome compared to mixed arrays in APL.


Fair enough. Like most APL I wrote it backwards until it worked.


Works out-of-the box in GNU APL as well, if someone wants to try it with a free version of APL.


To that end, my K version can be tweaked slightly to work with oK, an open-source interpreter based on k6:

    {(x;"Buzz";"Fizz";"FizzBuzz")@2 2/~3 5!\:x}'1+!20
k6 swapped the argument order of "mod" and made change of base into an overload of "/", rather than a named builtin. See it in action here:

http://johnearnest.github.io/ok/index.html?run=%20%7B%28x%3B...


"Doesn’t it make sense that in mathematics, we use the integral symbol instead of A.Integral(B)?"

In my experience the obscure notation is what made college math hard for me to learn. As a programmer I really wish there was a math textbook that used A.Integral(B) type notation to teach concepts, because I think I could have been good at math.

I realize that people who start with math have the opposite experience; my physicist friend complains that whenever he has to use a CLI or write code everything seems arbitrary and confusing to him.


I would be reading math-savy papers 3x as fast if they just declare the variables explicitly before equations, instead of definitions scattering all around the paper..


And I really hope the future for math be some lisp-like syntax where no special syntax is required every new concept is introduced.


Agreed. And to me it's not just the math notation that bugs me, but the tendency of mathematicians (and perhaps by extension, physicists) to always use one-letter variables.

In software development, you'd get torn apart in code review if your variables are all one letter long. Why is math so terse?


I think it's pattern matching and intuition. If I see y = k/x, I can immediately process what that looks like. Further, I can take advantage of tons of conventions that make it read differently from a = b/c or even y = z/x. The conventions take some getting used to, but after a while writing out dependentVariable = divideBy(constant, independentVariable) would get super tedious and it's absolutely not instantly pattern matchable. Especially when you're working out some manipulation where you have to write the same variable a zillion times, and maybe even depending on your brain's pattern matching and inspiration to kick in. Hell, at this point I even use a shorthand for cos and sin for those reasons.


I’m sure part of the reason is that mathematics was, and largely still is, written by hand. You can manipulate “code” more easily on paper with a terse, implicit notation. It can also have the advantage of engaging your visual pattern-matching abilities more than prose or prose-like notation.


Part of the reason is that most variables do not have much meaning.

What name do you ascribe to "a continuous function from R to R"?

Another detail is that you are rarely juggling more than 10 or so names at once.

A lot of math at a higher level becomes abstract enough to where elements no longer have a concrete meaning. What does the x in integral(f(x)dx) mean? It's more about some things being harder to write in point free style rather than anything else.

This is perhaps why it's common to have short names for arguments in functional languages as well.


I have had several opportunities to write Mathematica code in a style similar to this. Specifically, building up functions to map over entire lists rather than iterating over them.

Each step feels very intuitive and satisfying. But when you just look at the end result of any non-trivial example, it nearly always looks unreadable. I found myself needing to work quite hard to understand functions I myself had written, even if I was only interrupted by lunch.


  > 1{::(('FizzBuzz';'Fizz';'Buzz';":) 1337)

  Fizz
Is equivalent to:

  > ['FizzBuzz', 'Fizz', 'Buzz', 1337][1]

  Fizz
In a language with less foreign syntax. You can make it more familiar by putting the index on the right side of the array with '~':

  (('FizzBuzz';'Fizz';'Buzz';":) 1337){::~1

  Fizz
This is the modulo bit:

  (0 i.~15 3 5|])


I think comparing it with other languages may make it easier to grasp. Sometimes it's good to test it in a language you are used to. The selector expression could be represented in Python like this:

  a = lambda n: [n % x for x in [15, 3, 5]].index(0)


Yep, I started writing this out (first in js, but it doesn't map well, python list comprehensions do) but you beat me to it. :)

Now great, you can get the weird syntax and unroll it if you squint. Why is it written like this? Isn't it wasteful to test against all three cases (15,3,5) instead of returning early?

Probably has something to do with 'thinking in arrays' and how its a cheap comparison and that there's probably matrix multiplication or bit twiddling going on under there. That's the interesting bit to me.

To get the feel for an array language. This fizzbuzz example is actually surprisingly interesting because of that.


In fact, it's still not the same. In Python, the following expression will raise a ValueError.

  > a(2)
In J, it will return the length of the array, as stated in the post.


'explained' I read it twice and still don't understand what it's doing.


Author here. Sorry to hear that. If you want to let me know where I lost you via email or here, I'd be happy to revise it to be clearer.

I think it takes a certain skill to overcome the curse of already knowing something and then explaining it, and I'll definitely have some blind spots.

Thanks for reading it twice!


Consider that on HN there are surely people who read about J the first time, or if they have read something somewhere, they already forgot it and they won't go through the whole tutorial (which is not small) before reading the article.

For example, I guess that the

FB"0 >:i.100

is a kind-of for loop, even if I also guess it's not called as such in J, but I wouldn't be able to explain how it exactly works, except that >: is bigger or equal, which I glimpsed from some first page of the tutorial, and i. should mean index of, according to your text? But searching 100 in what? Or is it some new word?

Then, why was 1337 introduced in the explanation at all? I failed to understand, reading the text not too slowly.

Thanks for posting the article here, it's refreshing.


FB"0 basically means apply FB to each cell in an array. i.100 makes an array of numbers 0...99 and >: increments every number in that array by 1

So it's mapping FB over the numbers 1 to 100.

Now I don't know j very well so I don't know why this evaluates as (FB"0) (>:i.100) instead of (FB") (0>:i.100) but I guess " is special

1337 is just a stand in number. To try the algorithm without mapping it to an array.

So the algorithm is this make an array of [fizzbuzz fizz buzz x]. Then make an array of x mod 15, 3, 5. Find the first instance of 0 in that second array and use that index to select fizz,buzz etc. If there isn't a zero (0 i. secondarray) returns the length of secondarray which is 3, the same index as x in the first array.


Thanks! So I made more than one bad guess. So >: can be monadic, increment and dyadic, bigger or equal. And i. can be a generator or an index of.

But how to avoid reading the wrong meaning? If I'm reading right to left, I read 100, then I see i. then see something on the left of i. then why is it not a dyadic i. ? Because there is no parenthesis?


> But how to avoid reading the wrong meaning?

The only thing other than "practice" you can do is to use built-in J expression pretty-printer. It shows you a graph of an expression, grouping verbs with their arguments. I don't remember how to get to it exactly, I think it was somewhere in foreigns.

EDIT: it's even mentioned in the article, don't know how I missed it: 5!:4


Thanks. I've seen it but now that you mentioned I really liked to also understand what that means semantically:

5!:4 <'FB'

I see here:

http://www.jsoftware.com/help/dictionary/dx005.htm

That every combination of two numbers means something special.

http://www.jsoftware.com/help/dictionary/dx018.htm

Wow.


In this case i. is monadic because the thing to the left (>:) is a verb(function). It can get ugly because J has weird precedence/associative rules to let it be tacit but this isn't one of those cases

>: Is monadic because I guess " is special? And has a higher precedence than other things?


" is conjunction, it binds to its arguments - in this case left FB and right 0 - stronger than those bind to their arguments. >: is verb, i. another verb, so

>: i. 100

is understood as

>: (i. (100))

- as two monadic (one-argument) functions applied sequentially.

To the left of that application sits the next verb -

FB"0

which applied next, so the whole thing is

FB"0 (>: (i. (100)))

Precedence/associative rules are: all verbs from right to left, all adverbs/conjunctions from left to right, adverbs/conjunctions are higher by precedence than verbs. That's it.


>Precedence/associative ... That's it.

Until you get to hooks and forks.


Well, we also didn't mention foreigns (like, functions dealing with OS), punctuation, predefined nouns. Hooks and forks also deserve a description, even though I don't think this is about "precedence/associative" matter - both hooks and forks as a whole are verbs, so verbs rules apply.


J makes my brain hurt, but in a much saner way than thisCamelCasedVariableNameIsNotNearlyLongEnoughToBeSufficientlyClear...WhereWasIGoing?

So, props.


There's a blog post about FizzBuzzBazz (note the third value) in LiveScript, I posted a comment there, with J version[1], looking like this:

    fu=:(3&|),(5&|),:(7&|)
    g1=:(,&'zz')"1>;:'Fi Bu Ba'
    ((0=fu i.101){"1(3 1$<''),.(,.<"1 g1)),<"0 i.101
Well, what else can I say? J is really fun to play with.

It's also not true that it cannot be maintainable or readable. J crazy parsing rules and other language features make it very flexible, on the level of Lisp, TCL, PERL, Smalltalk or Io. This means it can be a completely unreadable mess, as well as a readable and maintainable code, depending on who writes it. I made an attempt at writing readable - articulate - J: https://klibert.pl/posts/literate_j.html

[1] http://livescript.net/blog/fizzbuzzbazz.html#comment-1145818...


That cryptic code, ironically, doesn't appear significantly shorter, if at all, than the FizzBuzz solutions in some ordinary, readable languages. What's the point?


I really like the concepts in APL/J. It's probably why I'm so excited to see more array oriented support in Perl6. Keep up the postings.


If you enjoy APL/J then you might want to check out F-Script on OS X. It was pretty fun for combining arrays with Smalltalk like syntax and might provide you with some amusement.


I found your post very compelling. I have tried messing around with the APL derivatives (J and K and Q), but never created anything substantial. I didn't know you could view the AST like that, and it did really help in your explanation. I'm definitely going to check out an APL again! Thank you for the great post!


I tried my hand at a terse fizz buzz, once. https://twitter.com/taeric/status/250060748548624385

Not really hard to come up with, but does take effort. Would be difficult to go through that for all programs.


It's been a while since I used J, but as I recall it's more idiomatic (though sometimes trickier) to write a function that works directly with arrays than to write a function that works with scalars and then to map it over an array.


If the string 'FizzBuzz' appears in your code, you have failed FizzBuzz.


How do you mean?


Typically, because there is (usually, not always) a more elegant solution when one recognizes 15 = 5 × 3 so you can avoid the need for a separate case to handle divisibility by 15.


Ah, I misread that to be either fizz or buzz.


:('Equilateral';'Isoceles';'Irregular';'Impossible'){::~3&,@<:@#@~.{~2&*@(>./)<+/

Belongs in https://www.stilldrinking.org/programming-sucks

In other words: I would not want to work with a language like this because I know most of the work is maintenance and it's hell if you need to work with something this sigil heavy.


As someone who loves J (though I'm far from mastering it), I certainly wouldn't want to work with it either. J (and APL) really shines when you're playing with it in interactive mode, gradually building sentences and looking at the output at every step. In my case, I've been using it to experiment in algorithmic composition, and I find it forces me to think in interesting and potentially powerful ways.

But, as you say, browsing through a large codebase in J would be not be a fun experience. The only way to handle it for me would be to comment it heavily and keep each line as short as possible (which is indeed what maintainable J files tend to look like). So I reserve it for experimentation - and I'm finding it very adapted for the purpose.


What you say is true for most languages, however, it's different for J. The sigils you see are the whole language - there are only around 20 sigils, which are the core functions of the language. You only need to learn and remember them, you can then work your way through any kind of J code. It may go slowly at the beginning, but as you get used to the most often occurring ways of composing them you get faster.

In other words: you can't really say anything about how it feels to work with J without working with it for some time. This may be true to some extent with other languages, but J is unique/different enough to make this point especially true.


I worked with J for some time (in my free time) and I pretty much had to learn it from scratch 3 or 4 times. And if I had to use J right now I'd had to learn again because I literally forgot everything. The syntax, the words, the verb trains... everything is downright absurd.

I really wanted to like it so I could program in my phone, but it's just too absurd to work for me.

The basic idea I got from experienced programmers was: you don't code like that in the real world. Real-life code should look a lot more like code in other languages, with no tacit programming and a lot of redefining of one-char words into actual words to improve readability. Then... why would I code in J at all? And why am I not taught to code like that in J's help?


From http://www.jsoftware.com/help/jforc/culture_shock.htm#_Toc19... , a great book about J:

> I've looked at some J code. Every other character is a period or a colon. I've got spots before my eyes. How can anybody read this stuff?

> You'll get used to it. J has a great many primitives, and it's important to keep the names short so that you can fit a lot of computation on one line; so the names are either single characters, like >, or a character with a period or colon appended (>. and >:). The period/colon is just part of the name. Single letters with period/colon, like i., are also used for primitives. If you want to assign your own names to the primitives, you are allowed to, but pretty soon you'll want to go back to the shorter names to save space and typing.


There are a billion things against a sigil only language: it's near impossible to give you a helpful IDE (in a word-like language you can use autocomplete but how do you give ideas whether the user should use @ or ^ at a given point?), it's near impossible to search for code examples and such (the other day I was looking for code in any language at all that uses /PZ/u as a regular expression without success), you need to think twice before using any of the standard shell utilities on them and so on.


> it's near impossible to give you a helpful IDE (in a word-like language you can use autocomplete

What autocomplete you need in J? For verbs and conjunctions which are at most 2 letters long?

> how do you give ideas whether the user should use @ or ^ at a given point?

In the same way as IDE helps you to choose . or exp() ? They are completely different concepts, how can you mix them?

> it's near impossible to search for code examples and such

I think it's a common problem for complex code examples, in any language. You may, though, search for comments.

From http://www.jsoftware.com/help/jforc/foreword.htm#_Toc1917342... :

> C is a computer language; it lets you control the things the computer does. J is a language of computation: it lets you describe what needs to be done without getting bogged down in details

I think it's a great help. J doesn't just reduces typing; it also reduces the amount of things one needs to keep in the head to solve the problem.


When I implemented the GNU APL mode for Emacs, I tried to make it as much as an IDE as possible. I modelled it on SLIME, and it has a live connection to your runtime, and provides things like jump-to-definition and completion based on the functions available in the runtime.

I even coerced SES (the Emacs spreadsheet) to act as an editor for large arrays.

I would argue that I have suceeded at least partially, such that I can say that it's definitely possible to implement an IDE for APL.


A popular saying in APL world: an APL programmer solves a problem in 5 minutes, then spends the rest of the hour to polish the solution to perfection.

I doubt you'll need a lot of maintenance for short (and thought-out) solutions.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: