Hacker News new | comments | show | ask | jobs | submit login
PHP in a Tweet (emanueleminotto.it)
60 points by EmanueleMinotto on Oct 8, 2013 | hide | past | web | favorite | 57 comments



I enjoy PHP like I enjoy going home to see my family for the holidays. It's fun for a bit, the nostalgia makes me feel warm and fuzzy, and the familiarity of everything is very comforting. You quickly realize though that the grass really is a lot greener on the other side. You remember why you moved out of your parent's place and went out on your own.

It's hilarious looking at how cryptic these one-liners are, particularly when I consider that with languages like Ruby and Python you can do a LOT with a tiny little line if code.

As a side-note, one of my favorites is summing an array in Ruby:

  x = [1, 2, 3, 4, 5]
  x.inject &:+
  => 15


These "one-liners" are cryptic because they are complex, it's a what can you do in the smallest form possible. It doesn't require code readability. Obviously you wouldn't use a 120 character dependency injector. That's just silly. But you can make one in 120 characters.


I disagree. I think they're simpler because they're built of smaller numbers of orthogonal concepts. I think code like this is certainly more dense, but I find the consequence of that density is that I spend less time pattern matching and skipping over "things that look like common idioms" and more time thinking about how there large, powerful abstractions wire together to achieve the intended end.


In PHP

   array_sum([1, 2, 3, 4, 5]);


The GP's point is that Ruby doesn't require a built-in method that specifically sums an array to still get a clean, terse operation. You can use #inject to apply an arbitrary operation to (operator, last result, current element) and arrive at a result.

For example, given a list of numbers, you can generate a bitwise OR mask easily:

    [1,2,3,4,5].inject(:|)
What this does is iterate over the list and apply ($last_result | $current_element) and return the result, which is passed on as $last_result to the next iteration. $last_result is 0 by default. This is equivalent to (as of PHP 5.4):

    array_reduce([1,2,3,4,5], function($v, $e) { return $v | $e; }, 0);
Or prior to PHP 5.3:

    function or_mask($v, $e) { return $v | $e; }
    array_reduce(array(1,2,3,4,5), "or_mask", 0);
It's doable in both languages, but Ruby's functional language lineage and its object-oriented nature results in an exceptionally clean approach.


Prior to PHP 5.3 this could work as well:

    array_reduce(array(1,2,3,4,5), create_function('$v, $e', 'return $v | $e;'), 0);


I'm really glad that 5.3 got proper anonymous functions. Specifying function bodies as strings to be eval'd makes me twitch.


In case this was a serious entry... which I honestly can't tell.

The problem with array_sum is not that it's too long but instead that it's combined two rather specific bits of functionality into a fixed (if common) form, while the Ruby code separates the ideas of "folding" and "addition" allowing for many orthogonal creations.

To pick another favorite, in Haskell you could write

    Foldable.foldl1 (+)
which sums any foldable thing—anything which has elements which can be combined together one-by-one. So it'll apply to Trees or Sets or Dictionaries (well, Maps) just as easily while also allowing things like (+) to be replaced by other binary operators.


PHP does have array_reduce, however operators like '+' can't be used as callables so you'd have to make your own wrapper functions.

Edit: Screw it, haven't self promoted on a while. In Pharen (https://github.com/scriptor/pharen), which compiles to PHP, you could do:

    (reduce (+) 0 [1 2 3 4 5])


That's really cool, but the syntax is strange to me. How do you distinguish between operator sectioning (+) and a side-effecting function call (f)?


It works (superficially) similarly to how Haskell does things and treats (+) as a partial function call by recognizing that + isn't getting at least 2 arguments. You could also do stuff like:

    ((+ 1) 2) ; => 3

    (map (* 2) [1 2 3]) ; => [2 4 6]
If a function f takes any arguments and Pharen knows this, it'll convert (f) into a partial function call as well. Unfortunately I haven't figured out a way to check if a function has any side effects. Otherwise in this case at least operators are treated like functions.


So it's tracking the arity of functions and turning anything which has been applied to fewer than ARITY arguments to a partial application?

I suppose that comes at the cost of (+ 1 2 3 4)?


It does track the arity of functions, but remember that this happens at compile time. Regular addition in Pharen is still just regular addition in PHP:

    (def a (+ 1 2 3 4)) ; => $a = (1 + 2 + 3 + 4);
Of course, there are situations where partial application won't always happen because the compiler is unable to detect it:

    (fn add (x y)
      (+ x y))

    (map #add [1 2 3])
Pharen won't be able to realize that `add` here is being partially applied inside `map`. It's not smart enough for that yet. If you try to run this you'll end up with 'Missing argument 2' and 'Undefined variable: y' all over the place.

However, I'm not putting a whole lot of emphasis on partials. They're there as a convenience, but they're not really a core part of the language.

But yes, back to the original point, all the tracking is done at compile time so that for addition with two or more arguments the resulting PHP will look like regular addition in PHP.


Gotcha, very interesting!


Surprisingly, not really.

    {-# OPTIONS -fglasgow-exts #-}
    
    class BuildList a r  | r-> a where
      build' :: [a] -> a -> r
    
    instance BuildList a [a] where
      build' l x = reverse$ x:l
    
    instance BuildList a r => BuildList a (a->r) where
      build' l x y = build'(x:l) y
    
    varargs x = build' [] x
    
    main = print $ ( sum $ varargs 1 2 3 4 5 6 100)


    $ ./Test
    121

    
http://okmij.org/ftp/Haskell/vararg-fn.lhs


I love that example, but it does depend upon some pretty arcane features in Haskell's type inference engine.


Why would it?


My hypothesis was that the compiler was tracking the arities of each function in order to open up opportunities for partial application. That means there's some ambiguity when you write something like (+ 1) which, in Scheme is a complete application equal to 1 but may also be interpreted as a partial application equal to (lambda (x) (+ 1 x)).

There are many ways to mitigate that ambiguity statically and dynamically, but I feel there's always going to be a tradeoff between favoring partial application, favoring variadic functions, and the complexity/sophistication of your static checking or runtime environment.

I just made a stab at where the solution might lie in that design space. Turns out I was wrong.


Well how about this then.

    foreach(array(1,2,3,4,5) as $x) $i=$i+$x; echo $i;


The array_reduce answers get closer to what I was looking for. This might be a "one line" answer, but it requires two special forms, assignment, sequencing operators (;), and two fresh variables.


This works, is fast enough and readable. Perfectly fine solution to me.


1. Separate folding and addition.

2. ?

3. Profit.


Orthogonality and composability dramatically increase abstraction, code reuse, testability, and likelihood of writing correct code, both for library maintainers and library users.

Step 2 is actually extremely well known.


array_sum_of_1_2_3_4_5();

(Added in PHP 6)


the funny thing is, with proper abuse of __call you can almost get that to work: https://gist.github.com/kennethrapp/328b6bd1bda8a8f94092


That's not funny. Horrifying, maybe, but not funny.

Edit: Strike 'maybe'. I looked at it again and it's definitely horrifying. I saved it anyway, though; Halloween's only a few weeks off, and I think I shall print it out and stick it on the wall of my cube next to the PHP hammer and the "periodic" table of Perl 6 operators.


kudos. almost as cool as the cpp template hack to compute area based on part of the source code 'ascii art' size. (which I can't find anymore. googlefu--)


Made me laugh :)


    irb(main):001:0> x = [1,2,3,4,5]
    => [1, 2, 3, 4, 5]
    irb(main):002:0> x.inject &:*
    => 120


Or one true line in APL:

    +/ 1 2 3 4 5


Since we are golfing...

+/⍳5


Here it is in Perl6:

  [+] ^6
Actually cheated slightly because ^6 creates list from 0..5 :)

So correct match would be...

  [+] 1..5
Here's how you would do it in Io:

  list(1, 2, 3, 4, 5) reduce(+)
In Rebol there isn't a functional fold/reduce built in. So one way to do the one-liner would be:

  x: [1 2 3 4 5] forskip x 2 [insert x '+] x: do next x
Above changes x to 15. Alternatively approach which doesn't clobber x:

  x: [1 2 3 4 5] y: [] forall x [repend y [x/1 '+]] take/last y do y
I'm sure someone with more Rebol chops can see other (better!) ways of doing this :)



Yeah, but remember to pass the 0 to it; otherwise the sum of an empty array would be nil:

  x.inject(0, &:+)
That's one of the disadvantages of not having a powerful type system to infer what's the "zero" of some type.

Still, the Ruby code is pretty readable and a good example of orthogonal concepts that compose well. E.g., getting the product of the numbers instead: x.inject(1, &:*). Or the least common multiple: x.inject(&:lcm).


[1,2,3,4,5].reduce(:+) Or in case of a range ... (1...6).reduce(:+)

I'm sorry i couldn't fight the urge to FIFY :( ...


It's a good fix and no bad thing to point out, and I'm not just saying that because I was about to point out the same thing before I noticed you'd beat me to it.


people have been creating 140 character music pieces in the supercollider music language for a while. its very tricky to make something that lasts and evolves and has structure and keeps your interest.

here are some great ones:

http://fredrikolofsson.com/f0blog/?q=node/478

play{a=SinOscFB;sum({|i|a.ar(a.ar(a.ar(a.ar(i+1,1/9,999),1/9,a.ar(1/9,1,1/9)),a.ar(0.1,3),i+2999),a.ar(1/9,1/9),1/9)}!9)!2}//#SuperCollider

r{loop{x={GVerb.ar(MoogFF.ar(ClipNoise.ar0.4,LFPar.kr({0.3.rand}!2,0,600,990)),9,9,1)}.play(s,0,19);3.wait;x.release}}.play//#SuperCollider

audio examples on the page above


this one is amazing:

play{a=LFPulse;b=(1..4);Mix(a.ar(a.ar(a.ar(a.ar(b/32)+1/8)+1b)+(Mix(a.ar(b/64))+a.ar(4/b)(a.ar(a.ar(b/8))2+b))100))/8!2}//#SuperCollider

audio:

http://fredrikolofsson.com/f0blog/files/audio/tweet0020.mp3

"this tweet is also totally deterministic and without any randomness. here a lot of nested square wave oscillators creates the complexity. basically there are 4 channels/voices mixed down to one and then duplicated in left and right channel. there are three levels deep nesting of frequency modulation with another set of square waves mixed and added."



Yeah I remember those ! In fact I did some bit shift melody stuff myself in supercollider based on those and some other code.

One of the sc people released an iPhone app that let's you write bitshift based melodies.

The early stuff that supercolliders creator James McCartney did really set the style for short, mathematically elegant music. It's really a great language for it. You can do operations on arrays, and do interesting multichannel expansion.


At the risk of arousing some people's ire, I really like these tidbits that try to squeeze maximum functionality (albeit a bit dangerous) into a minimum span of characters. It feels a bit like the underhanded C contest in a way since there are so many magnificent ways to self-destruct doing this, but at the same time it's a fun challenge.

A while ago, I put together a dirt-simple URL shortener https://twitter.com/eksith/statuses/275709375665037312

A bit of background: http://eksith.wordpress.com/2012/12/03/id-obfuscation


You might find Rebmu interesting, its a Rebol dialect designed for code golfing - https://github.com/hostilefork/rebmu

Here's a fun(!) presentation of Rebmu given by Dr. Rebmuthalamonious Golfstanipetrovitch (!!) given at the recent Rebol/Red conference - http://www.youtube.com/watch?v=iDKaz1iB9wQ

Enjoy! :)


That was wonderful. Thank you! :D


About ID obfuscation: i like to use a small-width block cipher (e.g. 32-bit skipjack). A reversible int->int transform means you don't need an extra DB column, you're never prone to CRC32 collisions, you can still use base36 (why not case-sensitive base62?) for URLs, and with an application secret key there's no chance of reversal.

Well, maybe someone could aim to get many sequential keys and then reverse-engineer the state of the cipher, but that's also possible with your method.


You might also like:

http://www.reddit.com/r/tinycode


Wow! I do also like that. I like that very much! Thank you for pointing me to that.


The Code Golf SE site is fun too: http://codegolf.stackexchange.com/


Don't invite Perl to this party


Too late, and she brought JavaScript too...


Wow, Perl's seen better days but I think they're a good match for each other. Perl's fascinated by JavaScript's objectivity and popularity, and JavaScript's wearing Perl for retro effect like some kind of fashion item. The two of them are like darkness and light. No prize for guessing who brought the drugs...


Unfortunately it's only available via WayBackMachine now but there was a fun Webapp in a 140 character tweet challenge back in the day (2009!) - http://web.archive.org/web/20111221094809/http://f055.net/ar...


There was something similar with JavaScript called 140byt.es [1]

[1] http://140byt.es/


I see your PHP and raise you this Perl:

http://pastebin.com/7UqSFWz7


I raise PHP and MySQL in a Tweet.

http://bit.ly/1hA9mZn


I'm really conflicted on what opinion to have of this. On the one hand, these PHP constructs are even worse than most of what you see in that language, but on the other hand, constraining PHP sources to a maximum length of 140 characters should help reduce the scope of the contagion.


The first one isn't very good. The slashes are optional anyway. http://bits.blogs.nytimes.com/2009/10/12/the-webs-inventor-r...


A friend of mine has an MVC library where each component fits in a tweet: https://github.com/jeremeamia/tweetmvc-core/blob/master/twee...




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

Search: