6 ms·
Wow, if you completely change the language to make it more verbose, it becomes more verbose! Incredible.
by rak1507 4y ago
Wow, if you completely change the language to make it more verbose, it becomes more verbose! Incredible.
- thesz 4y agoI glad you liked it. The transformation employed is used in application of Halstead metric [1] to various programming languages. [1] https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.106.8419 https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.106... APL/K and concatenative languages are not there, but Haskell is. What is fascinating is that Haskell wins by large margin because it uses implicit "apply" operation in place of space between expressions' parts. Something similar can be the case of APL and Joy/Forth as well. It appears to me that APL/K construct operations using implicit operations' stack. In case of Haskell, there would be an (infix) operation to perform something like that, much like what is discussed with the "implicit apply" in the paper above. In case of Joy, there is a stack of stacks (or list of lists).
- rak1507 4y agoThe link you provided doesn't seem to work for me. I don't think it's a particularly useful metric anyway, as the actual code matters a lot, not just the semantics. Also, those examples were very simple ones, and APL has a lot of handy composition features[1] that make function composition the best in any language I've tried, including Haskell. For example (+/÷≢) in APL is (liftM2 (/) (foldl1 (+)) (fromIntegral . length)) in Haskell. [1] https://aplwiki.com/wiki/Tacit_programming#Trains https://aplwiki.com/wiki/Tacit_programming#Trains
- thesz 4y agoI have several questions about your APL example. Why did you use (foldl1 (+)) instead of sum? Also, (fromIntegral . length) is (genericLength) - and that means you used implicit type conversion which may add terseness and also lead to errors. After all that, your example becomes (liftM2 (/) sum genericLength). Not much longer than APL's in terms of actual symbols used. APL fails differently, I think. It may very well fail you if you try to express parsing combinators, especially when context sensitivity and/or non-determinism are important.
- rak1507 4y agoI used foldl1 (+) because that's the literal translation of +/. I used (fromIntegral.length) instead of genericLength because genericLength requires an import (as does liftM2 actually, so I should've used that). 'Not much longer than APL's in terms of actual symbols used.' - well, there's liftM2, and for longer examples, chaining it is even worse - (f g h i j) in APL becomes liftM2 g f $ liftM2 i h j -> quickly becoming unwieldy and unclear. A lot of people also seem to say 'oh well if each character was a word it would be the same', and while it seems like that might be true, in practice it isn't, and the use of symbols allows for pattern recognition that you just don't get with words.
- thesz 4y agoAs I mentioned elsewhere, words are read as if they are hieroglyphs [1]. [1] https://www.mrc-cbu.cam.ac.uk/people/matt.davis/cmabridge/ https://www.mrc-cbu.cam.ac.uk/people/matt.davis/cmabridge/ You used monadic interface, instead you may use applicative interface. liftM2 then become liftA2 and what you exemplify above (if I understand that correctly) will render as (g <$> f <*> (i <$> h <*> j)). It is unusual, because "g" goes before "f", but not much unusual. Note the explicit pure function application in the use of <$> and explicit apply <*>. I would like you and other readers compare that to the implicit apply in the "Are ours smaller than theirs?" paper I provided link above. That translation shows what APL hides in its implicits. Let me repeat. APL will certainly help you with computations over arrays but will most probably fail you big time with parsing of something like Ada. Haskell won't fail you in both cases at the expense of slightly more verbose program text. Tacit programming exposes the need to "normalize" programs, to express them with as less function argument rearragement as possible. In stack based languages this is guided by the dependence on the stack(s) (data, return, control, whatever you invented). In point-free programming in Haskell, this is guided by argument capture and propagation. In K (I mostly studied it), as I understand it, tacit programming is guided by the implicit operations upon the stack of actual operations. These variants of tacit programming are mostly the same, just some cases are more easily expressible or some operations conveniently assumed to be implicit.
- PeterisP 4y agoWhat I'm reading in the parent post is an assertion that any verbosity that's simply replacing a word with a weird symbol (that's going to be spoken or thought of as a word anyway) is not true verbosity but just an illusion of it. Some languages express the same thing with more or less concepts, and more or less explicit complexity, and that is a true difference in verbosity, but symbol-vs-word is just a superficial difference that can and should be ignored for a useful comparison.