Elm:

If you have worked with AJAX or node.js or any other callback heavy framework, you have probably been to Callback Hell. Your whole application ends up being passed around as callbacks, making the code extremely difficult to read and maintain. The resulting tangled mess of code is often pejoritively called spaghetti code, a term borrowed from the days of goto.

Offensichtlich findet der Autor von Elm Callbacks beschissen. Er untermauert seine Argumente mit folgendem Snippet:

 1function getPhoto(tag, handlerCallback) {
 2    asyncGet(requestTag(tag), function(photoList) {
 3        asyncGet(requestOneFrom(photoList), function(photoSizes) {
 4            handlerCallback(sizesToPhoto(photoSizes));
 5        });
 6    });
 7}
 8
 9getPhoto('tokyo', drawOnScreen);

Und in der Tat, so sieht die Callback Hölle aus. Ich war dort. Und aus eingangs erwähnten Gründen sieht guter JS Code so nicht aus. Ein Framework, welches einen zwingt, die Applikation in Model, View und noch was aufzuteilen (z.B. Backbone), hilft schon sehr viel. Oder, wenn das Overkill ist, Javascript Promises einsetzen (Elm Beispiel mit Promises):

1var deferred_photos = requestTag( tag );
2var deferred_photo = requestOneFrom( deferred_photos );
3drawOnScreen( deferred_photo );

Der Code ist jetzt mindestens so gut zu lesen wie die Lösung in Elm:

1getPhotos tags =
2    let photoList  = send (lift requestTag tags) in
3    let photoSizes = send (lift requestOneFrom photoList) in
4        lift sizesToPhoto photoSizes

Trotzdem hat Javascript gegenüber Elm einen Nachteil. requestOneFrom sieht generisch aus, erwartet aber, dass der Input

  1. ein jQuery Deferred Objekt ist,
  2. irgendwann aufgelöst wird und dann
  3. Fotos via der Flickr API abgerufen hat.

Das sind gleich drei implizite Abhängigkeiten. Vergleichen wir das mit Elm. Dort will die Methode Fotos von der Flickr API als Input. Also genau das Interface, was ich erwartet hätte.

Bottom line: Der Code in Elm ist wiederverwendbarer als in Javascript , auch wenn das Eingangsbeispiel nicht der Realität entspricht (/update). Lesbarer würde ich gar nicht unbedingt als Argument bringen, siehe etwas komplexeres Elm:

 1requestOneFrom photoList =
 2let { getPhotoID json =
 3      case findArray "photo" (findObject "photos" json) of
 4      { (JsonObject hd) : tl -> findString "id" hd ; _ -> "" }
 5  ; requestSizes id = if id == "" then "" else
 6                          concat [ flickrRequest
 7                                 , "&method=flickr.photos.getSizes&photo_id=", id ]
 8  }
 9in  get (requestSizes (getPhotoID (extract photoList)))