Topic: Dopo Python? J!  (Letto 2610 volte)

0 Utenti e 1 Visitatore stanno visualizzando questo topic.

Offline riko

  • python deus
  • *
  • moderatore
  • Post: 7.453
  • Punti reputazione: 12
    • Mostra profilo
    • RiK0 Tech Temple
Re: Dopo Python? J!
« Risposta #15 il: Settembre 14, 2013, 00:02 »
- oop particolarmente orrenda (direte voi: e' un linguaggio funzionale, cosa pretendi? Posso rispondere sia con CLOS sia con OCaml).

Parli di S3 o di S4? A me sinceramente S3 non e' che dispiaccia... semplice e limitato, ma per quello che immagino di dovere fare con R...

S4 invece ha features decisamente interessanti. Ma con R non ho mai scritto molto, quindi non e' che abbia un'opinione particolarmente forte.
Probabilmente tutto lo schifo lo ho semplicemente non incontrato o bypassato visto la semplicita' dei problemi che ho dovuto risolvere.

Io personalmente trovo che in R ci siano veramente un mucchio di idiozie, ma giuro che mi sono commosso quando ho visto che le {} sono un operatore ridefinibile.
Non ho grokkato fino in fondo la cosa, ma a naso e' qualcosa che mi piace un sacco.

Offline riko

  • python deus
  • *
  • moderatore
  • Post: 7.453
  • Punti reputazione: 12
    • Mostra profilo
    • RiK0 Tech Temple
Re: Dopo Python? J!
« Risposta #16 il: Settembre 14, 2013, 00:05 »
O.o Pointless programming?! Che insolenza!

Cosi' si chiama, eh!

Citazione
Però in effetti fa perdere un sacco di tempo :D Non per il fatto di essere "tacit", ma perché risulta proprio come una sfida: perdo tipo 20 minuti buoni a convertire in stile "tacit" un verbo definito esplicitamente :D Alla fine, quando ci si riesce, è proprio una cosa splendida.

Ovviamente, ci rendiamo conto che questo e' un problema. E' un problema proprio perche' da soddisfazione, quindi uno vuole farlo.
E ovviamente alla fine della fiera non ha aggiunto nulla.

Citazione
Penso che quando mi sarò stufato con Project Euler in J, e quando avrò una solida conoscenza di J (quindi tra un bel po') passerò ad approfondire C, invece di imparare un nuovo linguaggio. Ho sempre evitato di andare a fondo ai puntatori, malloc e compagnia :).

Si ma guarda che non c'e' mica niente da capire... piu' che altro c'e' da fare esercizio, perche' i pattern di uso sono molto standard e dopo un po' e' solo una gran rottura di scatole da scrivere, ma a meno di esigenze estreme di velocita' si riesce molto a normalizzare C.

Offline riko

  • python deus
  • *
  • moderatore
  • Post: 7.453
  • Punti reputazione: 12
    • Mostra profilo
    • RiK0 Tech Temple
Re: Dopo Python? J!
« Risposta #17 il: Settembre 14, 2013, 00:09 »
Per i programmi grossi non credo sia un problema, a patto che tutti i contributori conoscano bene J e si attengano a delle linee guida.

Queste sono tutte ipotesi piuttosto pesanti da mettere sul piatto...

Citazione
Se il codice è commentato a sufficienza poi, non deve essere troppo difficile seguirlo

Pero' vedi, la pratica "moderna" si basa sull'idea che ogni qual volta ti senti di dovere commentare un pezzo di codice, dovresti usare il tempo per riscriverlo in modo che non abbia bisogno di un commento. Se sei in Java o in Python, direi che la cosa va via liscia. Se il commento e' l'unico modo di spiegare il codice, perche' il linguaggio e' troppo terso, abbiamo un problema.

Offline riko

  • python deus
  • *
  • moderatore
  • Post: 7.453
  • Punti reputazione: 12
    • Mostra profilo
    • RiK0 Tech Temple
Re: Dopo Python? J!
« Risposta #18 il: Settembre 14, 2013, 00:11 »
Citazione
La grande lezione del successo di Python nell'ambito scientifico è gli scienziati non sono hacker che fanno ricerca nel tempo libero, ma sono ricercatori che hanno medie (talvolta mediocri) conoscenze di programmazione,
E infatti usano quell'aberrazione che e' R.

Ma non direi sai... ho visto un po' di tutto. Ci sono comunita' che usano ancora Fortran (e li davvero tutti parlano fortan).
I fisici di solito lavoravano con C++ oppure con Matlab.
Solo gli statistici e i sociologi computazionali (che di solito vengono dalla statistica, o ne hanno fatta tanta) usano R.

E ultimamente stavo vedendo che Python sta davvero imponendosi *ovunque*.

Offline Flame_Alchemist

  • python sapiens
  • *****
  • Post: 509
  • Punti reputazione: 1
    • Mostra profilo
    • compscient
Re: Dopo Python? J!
« Risposta #19 il: Settembre 14, 2013, 09:26 »
Citazione
Parli di S3 o di S4? A me sinceramente S3 non e' che dispiaccia... semplice e limitato, ma per quello che immagino di dovere fare con R...
Alla fine S3 non e' OOP, e' solo sintassi, basata sulla notazione . (che non e' un separatore, ma un carattere valido nel nome, quindi...). In S4 si hanno inheritance e varie cose utili, ma la sintassi e' brutta ed e' in generale poco intuitiva (per esempio per dichiarare un metodo devi sapere se esiste gia' un metodo con quel nome in R, ed usare un procedimento diverso a seconda dei casi).

Citazione
Io personalmente trovo che in R ci siano veramente un mucchio di idiozie, ma giuro che mi sono commosso quando ho visto che le {} sono un operatore ridefinibile.
Non ho grokkato fino in fondo la cosa, ma a naso e' qualcosa che mi piace un sacco.
Sicuramente e' una cosa molto interessante, ma ci vedo pochi utilizzi che non rendano il codice un grosso WTF. -- ed e' uno dei motivi che lo rendono cosi' lento --.

Citazione
Volevano evitare di assomigliare a lisp...
In realta' e' basato su Scheme e la notazione infissa, che assomiglia a qualcosa di questo tipo: "+"(5 96) (con le " " attorno all'operatore) e' la piu' veloce.

Offline riko

  • python deus
  • *
  • moderatore
  • Post: 7.453
  • Punti reputazione: 12
    • Mostra profilo
    • RiK0 Tech Temple
Re: Dopo Python? J!
« Risposta #20 il: Settembre 14, 2013, 10:58 »

Citazione
Parli di S3 o di S4? A me sinceramente S3 non e' che dispiaccia... semplice e limitato, ma per quello che immagino di dovere fare con R...
Alla fine S3 non e' OOP, e' solo sintassi, basata sulla notazione . (che non e' un separatore, ma un carattere valido nel nome, quindi...).

Beh, pero' in tutti i linguaggi moderni OO e' *sintassi*, nel senso che la *semantica* (o meglio, le varie semantiche) si possono implementare in qualunque linguaggio.
Quello che manca in un linguaggio considerato "non OO" e' essenzanzialmente la sintassi. Per dire puoi scrivere C completamente ad oggetti, con tutto quello che ti pare (eredita', dispatch multiplo, etc etc etc), ma non avrai la semantica di un linguaggio ad oggetti.

Comunque anche in S3 hai ereditarieta', con NextMethod. E' semplicemente un modello di oggetto diverso da quello di C++, di Python... ma anche di Javascript.
Alla fine credo che il problema non sia tanto S3, ma il resto del linguaggio. S3 ne e' solo una conseguenza.

Citazione
In S4 si hanno inheritance e varie cose utili, ma la sintassi e' brutta ed e' in generale poco intuitiva (per esempio per dichiarare un metodo devi sapere se esiste gia' un metodo con quel nome in R, ed usare un procedimento diverso a seconda dei casi).

Eh...

Citazione
Sicuramente e' una cosa molto interessante, ma ci vedo pochi utilizzi che non rendano il codice un grosso WTF. -- ed e' uno dei motivi che lo rendono cosi' lento --.

Eh, sempre il solito problema. Quando permetti forte metaprogrammazione (e ridefinire {} ti da proprio questo) e' difficile avere performance decenti (a meno di non fare a compile time) e ovviamente c'e' il rischio di abusarne.

Citazione
Citazione
Volevano evitare di assomigliare a lisp...
In realta' e' basato su Scheme e la notazione infissa, che assomiglia a qualcosa di questo tipo: "+"(5 96) (con le " " attorno all'operatore) e' la piu' veloce.
[/quote]

Dici? Io scheme lo conosco abbastanza bene e oggettivamente R non me lo ricorda moltissimo. ;)
Cioe' scheme e' un linguaggio pulitissimo e ortogonale. R... beh, ecco.

Offline Flame_Alchemist

  • python sapiens
  • *****
  • Post: 509
  • Punti reputazione: 1
    • Mostra profilo
    • compscient
Re: Dopo Python? J!
« Risposta #21 il: Settembre 14, 2013, 17:44 »
E' una convenzione di nomi, alla fine. Che semanticamente e' OOP, certo. Pero', secondo me, se un linguaggio offre OOP dovrebbe anche dare degli strumenti comodi per ottenerla (capisco bene che questa sia questione di opinione, molto spesso, vedi in fondo). E, sempre secondo me, entrambi i modelli (S3 & S4) risultano imbullonati male al linguaggio originale.

Citazione
Comunque anche in S3 hai ereditarieta', con NextMethod.
Vero.
Citazione
Dici? Io scheme lo conosco abbastanza bene e oggettivamente R non me lo ricorda moltissimo. wink
Cioe' scheme e' un linguaggio pulitissimo e ortogonale. R... beh, ecco.
Vero, condivido la tua opinione su Scheme. Alcuni pezzi di semantica di R sono ispirati a Scheme. Un po' di macro (conseguenza del fatto che il parse tree e' direttamente accessibile), le conditions, i restarts (piu' Common Lisp, questo), e lo scoping lessicale; funzioni first-class e callCC (non identica a quella di scheme, piu' limitata, mi pare).
Credo che l'interprete core sia un piccolo interprete Scheme (o almeno, lo era). (e' un po' poco, pero' e' probabilmente piu' Lisp-like di Javascript, un altro linguaggio sempre considerato ispirato a Scheme).
Il risultato finale non e' dei migliori. (qualcuno dice che e' come il francese, cioe' ha un core molto elegante, ma fuori ha tantissime eccezioni -- io non conosco il francese, quindi non posso fare dei paragoni cosi' suggestivi)

Citazione
But from another perspective, the apply "method" of a closure can be used as a low-level method dispatch mechanism, so closures can be, and are, used to implement very effective objects with multiple methods. Oleg Kiselyov has a short article on the subject:
http://okmij.org/ftp/Scheme/oop-in-fp.txt
Used in this way, closures can be said to be richer than objects because they can support many more capabilities than just a single language-provided method dispatch mechanism. With closures seen as a building block with which to implement objects, it's clear that objects are a poor man's closures.

But a Smalltalker might say hold on, if you're going to all the trouble to implement these closure thingies in your language, since they're already a lot like objects, why not go all the way and make them "real" objects that can support an arbitrary number of methods, so that a closure is just one special-case kind of object?  If your language only has these restricted closures, and you're forced to build an object system on top of them, it's clear that closures are a poor man's objects.

Da: http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg03277.html

Offline riko

  • python deus
  • *
  • moderatore
  • Post: 7.453
  • Punti reputazione: 12
    • Mostra profilo
    • RiK0 Tech Temple
Re: Dopo Python? J!
« Risposta #22 il: Settembre 14, 2013, 19:20 »

Citazione
Vero, condivido la tua opinione su Scheme. Alcuni pezzi di semantica di R sono ispirati a Scheme. Un po' di macro (conseguenza del fatto che il parse tree e' direttamente accessibile), le conditions, i restarts (piu' Common Lisp, questo), e lo scoping lessicale; funzioni first-class e callCC (non identica a quella di scheme, piu' limitata, mi pare).
Credo che l'interprete core sia un piccolo interprete Scheme (o almeno, lo era). (e' un po' poco, pero' e' probabilmente piu' Lisp-like di Javascript, un altro linguaggio sempre considerato ispirato a Scheme).

Ecco... ma detto cosi' R sembra una figata. Cioe'... il fatto di avere call/cc e parse tree.
Devo decisamente guardarmelo meglio... il 2019 mi sembra un buon anno. ;)
Per restarts intendi le eccezioni che non distruggono lo stack? In tal caso vorrei capire come hanno fatto con call/cc, visto che e' opinione comune che non sia possibile implementare le due cose nello stesso linguaggio (o meglio, sia schemers che lispers ci hanno provato in vano da anni).


> Il risultato finale non e' dei migliori. (qualcuno dice che e' come il francese, cioe' ha un core
> molto elegante, ma fuori ha tantissime eccezioni -- io non conosco il francese, quindi non posso
> fare dei paragoni cosi' suggestivi)

Capisco. Io che di francese me ne intendo, tradurrei con "chi piscia troppo in alto finisce che si bagna". ;)


Citazione
Citazione
But from another perspective, the apply "method" of a closure can be used as a low-level method dispatch mechanism, so closures can be, and are, used to implement very effective objects with multiple methods. Oleg Kiselyov has a short article on the subject:
http://okmij.org/ftp/Scheme/oop-in-fp.txt
Used in this way, closures can be said to be richer than objects because they can support many more capabilities than just a single language-provided method dispatch mechanism. With closures seen as a building block with which to implement objects, it's clear that objects are a poor man's closures.

But a Smalltalker might say hold on, if you're going to all the trouble to implement these closure thingies in your language, since they're already a lot like objects, why not go all the way and make them "real" objects that can support an arbitrary number of methods, so that a closure is just one special-case kind of object?  If your language only has these restricted closures, and you're forced to build an object system on top of them, it's clear that closures are a poor man's objects.

Da: http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg03277.html

Conosco il pezzo... anche se preferisco la versione parabola zen.
Alla fine dei conti, come sempre, si confondono i problemi reali da quelli fittizi.

Cioe' il problema reale e' imparare a progettare ad oggetti in maniera sensata, cosa che non e' facile e non ho ancora trovato una metodologia "automatica" (e probabilmente non esiste). L'altro problema e' lo stile di programmazione stateful che spesso e' associato alla programmazione ad oggetti (ancora una volta, non necessariamente, ma in generale e' cosi').

Aggiungiamo il fatto che i piu' famosi linguaggi ad oggetti sono molto piu' scomodi da usare della maggior parte dei linguaggi funzionali sensati, e che quelli dinamici tendono ad essere vari ordini di grandezza piu' lenti e viene da chiedersi se in effetti qualcosa non e' stato sbagliato nel tutto.

Effettivamente il sistema di modularizzazione di SML e di Haskell a mio avviso risolve ben meglio della programmazione ad oggetti "classica" vaste categorie di problemi.
Ovviamente dovere ragionare quasi sempre in modo stateless (o dovere passare per monadi di stato) non e' esattamente comodo. Ed e' chiaramente una di quelle cose che rende certi linguaggi impossibili da imparare per buona parte di quelli che oggi fanno gli sviluppatori.

Offline Flame_Alchemist

  • python sapiens
  • *****
  • Post: 509
  • Punti reputazione: 1
    • Mostra profilo
    • compscient
Re: Dopo Python? J!
« Risposta #23 il: Settembre 15, 2013, 10:56 »
Citazione
Ecco... ma detto cosi' R sembra una figata. Cioe'... il fatto di avere call/cc e parse tree.
Devo decisamente guardarmelo meglio... il 2019 mi sembra un buon anno. wink
Per restarts intendi le eccezioni che non distruggono lo stack?
Yep, nelle conditions non viene fatto l'unwinding dello stack. Per esempio se si ha uno stack di chiamate di questo tipo:
H <-- solleva eccezione
G
F
D

(ovvero D chiama F, F chiama G e G chiama H).
[codice=Common Lisp](defun D (a b)
  (F a b))
(defun F (a b)
  (* 3 (G a b)))
(defun G (a b)
  (H a b))
(defun H (a b)
  (* 2 (/ a b)))[/codice]
(L'esempio classico della divisione per zero).
(D 1 2) ; ==> 1/2
(D 1 0) ; ==> DIVISION-BY-ZERO (il debugger presenta l'opzione di abort)

Definendo G in questo modo:
[codice=Common Lisp](defun G (a b)
  (restart-case (H a b)
    (return-default-value () 37)))[/codice]
All'invocazione di (D 1 0) il debugger presenta (anche) l'opzione RETURN-DEFAULT-VALUE, e, se selezionata, il valore ritornato e' il numero 37.
[codice=Common Lisp](defun D (a b)
  (handler-bind ((DIVISION-BY-ZERO
                  #'(lambda (c)
                        (print c)
                        (invoke-restart 'return-default-value))))
    (F a b)))[/codice]
Cambiando l'implementazione di D con questa, si ottiene:
[codice=Common Lisp](D 12 6) ; => 12 (= 3 * 2 * 12/6), se qualcuno avesse problemi con S-expr
(D 1 0)
; => #<DIVISION-BY-ZERO #x210129C13D>
; => 111 (3 * 37)[/codice]
Nell'ultimo caso si perde una * 2 siccome il restart e' impostato in G, e non in H.
#'(lambda (c) (print c) (invoke-restart 'return-default-value))
Questa lambda e' la funzione restart, e il parametro c e' la condition (che sono quasi equivalenti ad oggetti della classe Exception). La strategia di restart e' messa nelle funzioni di alto livello, di solito. La funzione di restart puo' essere piu' complicata, offrire piu' opzioni, ecc.
Ovviamente con questo sistema si possono fare delle cose molto interessanti, che permettono (per esempio) di entrare nel debugger e richiedere i dati; o modificare il programma, sistemare l'errore e fare retry, rimanendo nello stack di chiamata del debugger (che, notate, e' una funzione come le altre), ricompiere un errore e... inception. Sinceramente non so se il sistema di R (non credo che il debugger, seppure sia da un po' che non lo uso, sia paragonabile a quello di una implementazione Common Lisp), permetta di fare tutte queste porcate (nel senso buono, ovviamente) ma permette di avere eccezioni che non gambizzano lo stack, quindi e' possibile farne (almeno) un sottoinsieme.

Citazione
In tal caso vorrei capire come hanno fatto con call/cc, visto che e' opinione comune che non sia possibile implementare le due cose nello stesso linguaggio (o meglio, sia schemers che lispers ci hanno provato in vano da anni).
Davvero? Secondo questo http://programmers.stackexchange.com/a/80919 sono piuttosto semplici da implementare, e leggendo la documentazione di MIT Scheme sembra che li abbia.
CallCC e' solo downward (permette di uscire da chiamate ricorsive profonde). La continuation non e' piu' valida una volta che si e' usciti.
« Ultima modifica: Settembre 15, 2013, 11:26 da Flame_Alchemist »

Offline Flame_Alchemist

  • python sapiens
  • *****
  • Post: 509
  • Punti reputazione: 1
    • Mostra profilo
    • compscient
Re: Dopo Python? J!
« Risposta #24 il: Settembre 17, 2013, 09:27 »
http://www.mail-archive.com/haskell-cafe@haskell.org/msg107983.html

Un dialetto APL con typing alla Haskell potrebbe essere molto interessante (considerando che J ha gia' un typing forte con array omogenei). Mi interesserebbe vedere come potrebbero implementare i fork/hook (senza ricorrere a template haskell? anche se la vedo dura, a meno di ricorrere ad una notazione dedicata).

Offline riko

  • python deus
  • *
  • moderatore
  • Post: 7.453
  • Punti reputazione: 12
    • Mostra profilo
    • RiK0 Tech Temple
Re: Dopo Python? J!
« Risposta #25 il: Settembre 17, 2013, 22:00 »
http://www.mail-archive.com/haskell-cafe@haskell.org/msg107983.html

Un dialetto APL con typing alla Haskell potrebbe essere molto interessante (considerando che J ha gia' un typing forte con array omogenei). Mi interesserebbe vedere come potrebbero implementare i fork/hook (senza ricorrere a template haskell? anche se la vedo dura, a meno di ricorrere ad una notazione dedicata).

Beh, da quello che vedo di J non e' che strettamente parlando abbia tipizzazione statica come Haskell. L'unica cosa e' che appunto gli array sono omogenei.
Per il resto a me sembra un linguaggio piuttosto dinamico.

Per il resto, fork e hook non sono facilmente implementabili in Haskell puro, temo.
Non ho idea di quanto sia importante per scrivere J, ma da come lo presentate si possono aggiungere ad Haskell le *funzionalita'* di APL (per esempio nella manipolazione degli array), ma non la capacita' di scrivere funzioni "a la J", che evidentemnete hanno bisogno di fork e hook.

Offline riko

  • python deus
  • *
  • moderatore
  • Post: 7.453
  • Punti reputazione: 12
    • Mostra profilo
    • RiK0 Tech Temple
Re: Dopo Python? J!
« Risposta #26 il: Settembre 17, 2013, 23:16 »
Yep, nelle conditions non viene fatto l'unwinding dello stack. Per esempio se si ha uno stack di chiamate di questo tipo:

Chissa' se me lo ero dimenticato oppure non lo avevo mai saputo. Avevo letto un libro su R.
Il codice scritto in effetti era piu' che altro robetta per fare analisi statistica, piu' scriptini che programmi.
Quindi non mi sorprende troppo non essere familiare con la gestione delle eccezioni di R.

Citazione
Ovviamente con questo sistema si possono fare delle cose molto interessanti, che permettono (per esempio) di entrare nel debugger e richiedere i dati; o modificare il programma, sistemare l'errore e fare retry, rimanendo nello stack di chiamata del debugger (che, notate, e' una funzione come le altre), ricompiere un errore e... inception.

La vera verita'? A me piace l'idea delle eccezioni di Common Lisp. Mi piace davvero.
Riesco senza difficolta' ad immaginare quanto sarebbe bello averla.

Poi oggettivamente mi viene in mente quanto arbitrariamente ci si puo' fare male con una cosa del genere a meno di non essere piu' che rigorosi.
Finche' la usano in Lisp, con una comunita' minuscola e relativamente ben educata, tutto ok. Non oserei immaginare cosa potrebbe succedere se si arrivasse anche solo a Python come e' oggi.

Comunque non mi dispiacerebbe averli.

Citazione
Davvero? Secondo questo http://programmers.stackexchange.com/a/80919 sono piuttosto semplici da implementare, e leggendo la documentazione di MIT Scheme sembra che li abbia.

Allora, il pezzo originale non lo ho trovato. Piu' che altro ho trovato critiche di lisper sui problemi di  call/cc.
Qui un commento comunque interessante:

https://groups.google.com/forum/#!msg/comp.lang.lisp/1Ggl_BUi3Yg/VFTIDaJqRK8J

In realta' qui a lui da piu' fastidio la semantica dei with- che sarebbe da rimaneggiarsi, e, in definitiva unwind-protect, che e' il pezzo tosto dell'armamentario delle eccezioni di lisp da implementare in presenza di call/cc.

Non a caso, non mi sembra che GNU/Scheme abbia unwind-protect. Ma senza, hai bei problemi. No dynamic-wind non e' una soluzione veramente accettabile... ;)



Citazione
CallCC e' solo downward (permette di uscire da chiamate ricorsive profonde). La continuation non e' piu' valida una volta che si e' usciti.

No. In scheme call/cc ha scope indefinito. Purtroppo. Che e' il motivo per cui e' una di quelle idee belle sulla carta che non vorrei mai avere in un linguaggio da usare in pratica. Anche perche' la pezza e' dynamic-wind che... beh.

Offline Flame_Alchemist

  • python sapiens
  • *****
  • Post: 509
  • Punti reputazione: 1
    • Mostra profilo
    • compscient
Re: Dopo Python? J!
« Risposta #27 il: Settembre 18, 2013, 13:38 »
Citazione
Beh, da quello che vedo di J non e' che strettamente parlando abbia tipizzazione statica come Haskell. L'unica cosa e' che appunto gli array sono omogenei.
Per il resto a me sembra un linguaggio piuttosto dinamico.
Il typing e' dinamico ma forte. (per interderci, 2+'2' e' domain error). Sarebbe interessante vedere un dialetto/reimplementazione con typing statico. La vedo dura perche' fare il parsing di J e' difficile (gli interpreti fanno il parsing mentre eseguono).
Citazione
Per il resto, fork e hook non sono facilmente implementabili in Haskell puro, temo.
Non ho idea di quanto sia importante per scrivere J, ma da come lo presentate si possono aggiungere ad Haskell le *funzionalita'* di APL (per esempio nella manipolazione degli array), ma non la capacita' di scrivere funzioni "a la J", che evidentemnete hanno bisogno di fork e hook.
Si', credo anche io. Pero' credo che potrebbero servire anche ad Haskell in certi casi (ed, in generale, a tutti i linguaggi che favoriscono la composizione).
Probabilmente aiuterebbero ad evitare molti punti (di composizione tra funzioni) da aggiungere nelle definizioni point-free. Si guadagna molto tutte le volte che il parametro compare 2 o piu' volte nella definizione esplicita.

[codice=J]f =: - >./
f =: 3 : 'y - >./y' NB. equivalente alla precedente, non tacita[/codice]
In haskell la stessa cosa si puo' scrivere (modulo magari qualche parentesi che ho dimenticato)
[codice=Haskell]f = map (\x -> x - m) xs
    where m = foldr max 0 xs[/codice]

Sinceramente non so come sia in point free. Affidandomi al package pointfree su cabal, ottengo (o al lambdabot, se frequentate #haskell)

$ pointfree "(\xs -> (\m -> (map (\x -> x - m) xs)) (foldr max 0 xs))"
flip (map . subtract) `ap` foldr max 0

(E' stata riscritta per eliminare il where, usando la classica forma con lambda)

Chiaramente in questo esempio la prima forma di Haskell (quella esplicita) e' la piu' chiara, ma il verbo in J, una volta noto che `(f g) y' si traduce in `y f (g y)', e' tutto sommato leggibile. (Buona parte della semplicita' dell'espressione J deriva dal fatto che le operazioni tra vettori sono implicite)

Un altro esempio:
num_of_occ = (length .) . filter . (==) -- Haskell
num_of_occ =: +/@:=


Questo e' un esempio un po' piu' complicato (e' un pezzo della soluzione al problema 120 su project euler)
[codice=J]f =: * (<. &. -: @ <:)
NB. (f g) y => y f (g y)
NB. f @ g = f (g y) come il . di Haskell
NB. f &. g => h f g y (dove h e' l'inverso di g), e il resto sono funzioni.[/codice]
In Haskell, la stessa espressione:
$ pointfree -v "(\x -> x * 2 * div (x-1) 2)"
Transformed to pointfree style:
ap ((*) . (* 2)) (flip (div . subtract 1) 2)
Optimized expression:
ap ((*) . (* 2)) (flip (div . subtract 1) 2)
ap ((*) . (* 2)) (flip div 2 . subtract 1)
ap ((*) . (2 *)) (flip div 2 . subtract 1)
liftM2 (*) (2 *) (flip div 2 . subtract 1)


A parte ap e liftM2, che sono un funzioni un po' particolari, il resto e' comprensibile, ma ben lontano dalla semplicita' dell'espressione esplicita.
Ovviamente il problema che si sviluppa e' poi l'abuso del point-free. Che, in effetti, succede in J: ma d'altra parte, se scrivi in point-free hai un paio di cose utili gratuitamente: l'inverso (non sempre, ovviamente) e la derivata (simbolica, ogni tanto, numerica sempre) -- ok, cose che non sono indispensabili, ma ogni tanto possono essere molto comode, grazie ad under, ovvero `&.`.
L'abuso di una caratteristica e' un problema che esiste sempre, anche se la maggior parte delle caratteristiche presenti nei linguaggi di programmazione comuni, quando usate troppo, non fanno particolari danni (si', in Java per esempio si abusa delle eccezioni solitamente, quindi alla fine per esasperazione si mette un try/catch attorno al main, e poi quando non va qualcosa... pazienza, si perdono un paio di ore a guardare lo schermo e poi si arriva ad una soluzione).

Citazione
No. In scheme call/cc ha scope indefinito.
Si', il soggetto (tacito) era R. In R, callCC e' solo downward. Da quello che si legge in giro call/cc (di Scheme) non e' troppo usata, e molta gente vorrebbe le continuazioni delimitate (che tanto in pratica delimitate lo sono gia').

Offline riko

  • python deus
  • *
  • moderatore
  • Post: 7.453
  • Punti reputazione: 12
    • Mostra profilo
    • RiK0 Tech Temple
Re: Dopo Python? J!
« Risposta #28 il: Settembre 19, 2013, 23:11 »
Sinceramente non so come sia in point free. Affidandomi al package pointfree su cabal, ottengo (o al lambdabot, se frequentate #haskell)

Te lo dico io come e' in point-free. E' una pessima idea, ecco cosa e'!
Il fatto che, con sufficiente supporto sintattico, puoi scrivere *ogni cosa* in pointfree, a mio avviso non rende una buona idea farlo.
Mi sono laureato in matematica, sono abituatissimo a funzioni che prendono funzioni, spazi di funzioni, qualunque cosa con le funzioni.
Siamo abituati a definire funzioni strambe.

E posso garantire che il point-free si usa solo nei casi semplici, quando e' completamente ovvio cosa vuoi dire.
In particolare quando l'oggetto che ti interessa definire e' proprio una funzione, e i parametri non sono importanti, oppure sono veramente ovvi.

Quando le cose cominciano a diventare non banali, i parametri si mettono.

Quindi, sinceramente, quando devo definire

sum = fold (+) 0

mi va abbastanza bene. Salvo che siamo tutti consci che questo e' arabo per le persone "normali".
Pero' va anche detto che aggiungere esplicitamente xs non e' che migliora molto le faccende.
Lasciarlo fuori tanto vale.

Quando cominci ad avere un parametro che deve essere usato in piu' punti oppure che non e' banalmente spostabile in ultima posizione, secondo me le cose cominciano a non valere piu' la pena.

Posto che:

1. per il compilatore e' la stessa cosa
2. per gli umani e' sicuramente piu' leggibile la forma estesa (salvo appunto nei casi banali)

Una feature di un linguaggio per me deve essere usata per scrivere software migliore. Ho pensato un pochetto a come renderla point-free a mano.
Qualche idea mi e' venuta, ma a dire il vero dovrei lavorarci ancora. Il che indica chiaramente il problema: sono disposto a lavorare per fare refactoring, per rendere il codice piu' pulito. Alla bisogna, piu' efficiente. Ma il giochino del point-free, e' proprio pointless.

Citazione
Chiaramente in questo esempio la prima forma di Haskell (quella esplicita) e' la piu' chiara, ma il verbo in J, una volta noto che `(f g) y' si traduce in `y f (g y)', e' tutto sommato leggibile. (Buona parte della semplicita' dell'espressione J deriva dal fatto che le operazioni tra vettori sono implicite)

Se lo dici tu che e' leggibile, ti credo... ;)
Io non ho visto tanta punteggiatura tutta insieme dai tempi di brainfuck... :)

Per me leggibile e':
[codice]
def f(xs):
    m = max(xs)
    return [x - m for x in xs]
[/codice]

Citazione
Un altro esempio:
num_of_occ = (length .) . filter . (==) -- Haskell
num_of_occ =: +/@:=

Ribadisco... un giochino interessante. Ma non vorrei avere a che fare con 10.000 righe di giochini interessanti.
Detto sinceramente, quello la non mi sembra buon Haskell. Magari Haskell divertente. Magari Haskell che fa vedere quanto bene conosciamo Haskell.

Citazione
Ovviamente il problema che si sviluppa e' poi l'abuso del point-free. Che, in effetti, succede in J: ma d'altra parte, se scrivi in point-free hai un paio di cose utili gratuitamente: l'inverso (non sempre, ovviamente) e la derivata (simbolica, ogni tanto, numerica sempre) -- ok, cose che non sono indispensabili, ma ogni tanto possono essere molto comode, grazie ad under, ovvero `&.`.

Sono d'accordo. Nel caso di J posso capire che a volte tutto questo sia interessante.
Credo che sia parte dei motivi per cui nonostante sia in giro non da poco, non attragga troppa gente.

Citazione
L'abuso di una caratteristica e' un problema che esiste sempre, anche se la maggior parte delle caratteristiche presenti nei linguaggi di programmazione comuni, quando usate troppo, non fanno particolari danni (si', in Java per esempio si abusa delle eccezioni solitamente, quindi alla fine per esasperazione si mette un try/catch attorno al main, e poi quando non va qualcosa... pazienza, si perdono un paio di ore a guardare lo schermo e poi si arriva ad una soluzione).

Si, sono d'accordo. La gente abusa sempre delle cose. Per cui bisogna chiedersi quanto sia drammatico l'abuso per valutare la feature.
E' uno dei motivi per cui in Python non sono state aggiunte le lambda multi-linea...


Citazione
No. In scheme call/cc ha scope indefinito.
Si', il soggetto (tacito) era R. In R, callCC e' solo downward. Da quello che si legge in giro call/cc (di Scheme) non e' troppo usata, e molta gente vorrebbe le continuazioni delimitate (che tanto in pratica delimitate lo sono gia').
[/quote]

Ah, ok. Comunque in scheme, chi usa scheme, usa tantissimo call/cc. Anche perche' non e' che ci sia molto altro.
Incidentalmente call/cc ha problemi immensi e starebbe bene bandita in un linguaggio "di uso". Viceversa come tool di studio e' preziosissima.

Offline Aezio

  • python neanderthalensis
  • ****
  • Post: 327
  • Punti reputazione: 1
    • Mostra profilo
Re: Dopo Python? J!
« Risposta #29 il: Ottobre 25, 2017, 15:53 »
Citazione
Cos'ha di cosi' osceno R? (non e' una critica, e' ignoranza)
Cosi', in ordine sparso:
- = e <- sono uguali, tranne in un caso, molto specifico.
- implementazione standard particolarmente lenta;
- importare una libreria puo' cambiare le funzioni "built-in", (apply(ice.cream, 2, is.numeric) da' un risultato sbagliato, mentre aggiungere library(Hmisc) sopra lo fa funzionare)
- conversioni implicite. apply(...) converte automaticamente gli argomenti in matrici/vettori, anche se sono dataframe (che sono una bestia diversa).
- 4/5 (non ricordo) modi per accedere ad una colonna di un dataframe.
- N/A dappertutto quando si importano dati non completi, ma nessun warning. NaN e' una cosa diversa ma is.na(x) ritorna TRUE se x e' NaN.
- mille funzioni con nomi tipo sapply, tapply, vapply, etc.
- oop particolarmente orrenda (direte voi: e' un linguaggio funzionale, cosa pretendi? Posso rispondere sia con CLOS sia con OCaml).
- e, ultimo, aggiungere parentesi in piu' attorno alle operazioni rallenta l'esecuzione.
Sono cose che magari a qualcuno sono comode, ma ad un programmatore tipicamente lo fanno rabbrividire. Molte cose tra quelle che ho nominato (me ne accorgo ora) sono anche contro lo zen di Python.

Non so se il buon alchimista bazzica ancora da queste parti, ma dopo 2 settimane di full immersion in R ho sentito il bisogno di riesumare questo post per aggiungere un paio di cose alla galleria degli orrori sopra"

Vuoi sommare array di diversa lunghezza? Certo, in R si puo' fare:
> a <- c(1, 2)
> b <- c(3, 4, 5)
> a+b
[1] 4 6 6
Warning message:
In a + b : longer object length is not a multiple of shorter object length
>


Richiedi argomenti che poi non usi? Fa niente, questa funzione sotto funziona senza problemi se la si chiama solo passando a:

foo <- function(a, b) {
print(a)
}