Category Archives: Python

Una keyword che manca in Python

x0Ultimamente sono alle prese con Racket, l’ultima evoluzione del Lisp ma sono anche tentato da Haskell e in ogni caso continuo con Python. Ebbene sì, lo raccomando, quasi sempre😀
Recentemente ho dovuto modificare uno script di quelli che nascono al volo per un caso specifico, lunghi poche righe ma poi con il tempo crescono con il rischio di ingarbugliarsi da far invidia a brainfuck.
Non parlo di come si può evitare questo degrado stilistico, cose che si sanno (e a volte si mettono anche in pratica) ma di una caratteristica di Python: l’assenza dell’istruzione case (Pascal, Delphi) detta anche switch (C) e cond (Lisp) e … (OK, ha parecchi nomi).

In Python si usa if:

ifA parte l’estrosità di scrivere elif al posto di elseif o else if funziona. E siccome c’è solo quella si usa, e funziona benissimo.

Ma perché manca case? Visto che siamo quasi in periodo di feste (auguri, nèh!) e questo genere di post piacciono quasi-quasi interrogo il Web sull’argomento.

Parto da un documento ufficiale PEP 3103 — A Switch/Case Statement.
Dice in sintesi Guido che è ripetitiva, inefficiente, non ci guadagni niente, non rende il codice più chiaro, insomma: A quick poll during my keynote presentation at PyCon 2007 shows this proposal has no popular support. I therefore reject it.

Non tutti sono d’accordo, per esempio texasman1979: I wrote a Python Switch statement. Uhmmm… è stato giudicato non chiaro e unphytonic. Chiuso. Anche se vedi dopo.

L’argomento è sentito, ecco un altro post simile, questa volta pythonic (sembra): Michael Schneider, Replacements for switch statement in Python?
E la soluzione che io conto di mettere per ultima me la stanno spoilerando tutti🙄

Una ricetta diversa, C-istica viene proposta da Brian Beck: Readable switch construction without lambdas or dictionaries.
Riceve parecchi commenti, tra i quali “A very inventive approach!!! This is what I’d call an inspired solution. Of all switch-case substitutes, I probably like this one most“.

Più teorico l’articolo di Lance Finn Helsten, Python Switch Statement, ricco di notizie storiche, bello😀

OK, A questo punto mi sembra di aver messo parecchia carne al fuoco. Restano due questioni in sospeso:

  • cosa ho fatto per il caso cui accennavo all’inizio: ho aggiunto un elif, dovevo solo fare manutenzione dello script e me la sono cavata con pochissime rihe di codice;
  • in generale se dovesse capitare in futuro come mi comporterei? Non ne sono sicuro ma probabilmente i dizionari, sono la via, come descritti nel post lasciato qui in fondo. Ma forse ha ragione teh BDFL, come sempre (kwasy).

L’ultima parola spetta a PyDanny, Daniel Roy Greenfeld, tra le altre cose a fantasy novel author e former NASA python coder: Why Doesn’t Python Have Switch/Case? Tutto da leggere.
E se continua a mancarvi il case là c’è la soluzione😀

:mrgreen:

Un aiuto per i comandi Bash

11988Aggiornamento: corretto errore nella riga 12 dello script.
Un post che è solo un esercizio; ho visto che il precedente su un argomento simile è piaciuto allora ecco.
Si tratta di Bash, anche se lo script è in Python, versione 3, quella da usare sempre tranne casi particolari (p.es. WxPython non c’è ancora; ci sarà mai?).

Esiste una reference per Bash ottima, qui: Bash Reference Manual.
Potrebbe essere comodo poterla consultare in locale, ecco come.

Ho salvato in locale il file con il nome BRM.html e posso fare qualcosa come

b0

La parola cercata —printf— compare 12 volte ma il risultato è pasticciato e serve a poco. Notare però che l’ultimo hit ha un link:

<a href="#index-printf"><code>printf</code>

È un link interno (ovviamente) che voglio visualizzare con il nome assoluto, l’URL.
Con Python, usando una pipe è semplice, meno di 30 righe di codice, eccolo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/usr/bin/python3

import subprocess
import sys, os

if len(sys.argv) != 2:
	print('cosa cerco?')
	exit(2)

dirp = os.path.abspath(os.path.dirname(sys.argv[0]))
cerco = sys.argv[1]
command = 'grep -i ' + cerco + ' ' + dirp + '/BRM.html' 
prefisso = 'file://' + dirp + '/BRM.html'

proc = subprocess.Popen(command, shell=True, 
		stdout=subprocess.PIPE, 
		stderr=subprocess.PIPE)
proc.wait()
outp = str(proc.stdout.read())

ps = outp.find('<a href="#')
while ps >= 0:
	pe = outp.find('">', ps)
	trovato = outp[ps+9 : pe]
	if cerco in trovato:
		print(prefisso + trovato)
	ps = outp.find('<a href="#', pe)

Lo script è semplice, comunque:

la riga 10 dirp = os.path.abspath(os.path.dirname(sys.argv[0])) memorizza in dirp il path assoluto dello script e del file di dati visto che si suppone siano nella stessa directory.

le righe 15-18:

proc = subprocess.Popen(command, shell=True, 
		stdout=subprocess.PIPE, 
		stderr=subprocess.PIPE)
proc.wait()

eseguono una pipe con il il comando command definito precedentemente (riga 12).

il risultato viene salvato nella variabile outp, riga 19 outp = str(proc.stdout.read()). Popen restituisce una tupla di bytes per cui è necessario trasformarla in stringa con str().

A questo punto un ciclo righe 21-28 cerca le substringhe cerco all’interno dei possibili link, quelli con <a href="#. Siccome il link (trovato) può essere più lungo di cerco non uso l’operatore == ma in.

Provo:

b1

Adesso il motivo dello script: nel terminale quelle righe sono attive. Posizionando il cursore del mouse sopra uno e facendo click con il tasto destro ottengo

b2

e con Apri collegamento apro nel browser a quel link interno il manuale.

Non resta che dare un nome sensato allo script, renderlo eseguile e spostarlo in ~/bin, dove dev’esserci anche il documento HTML.

b3

Non mi è venuto in mente niente di meglio di baiuto, da Bash aiuto😀
:mrgreen:

Racket e l’arcotangente iperbolica

CNJ

In in precedente post era rimasta in sospeso una domanda: quanto vale l’arcotangente iperbolica di -2? A differenza di Common Lisp (CL) Racket liscio risponde male; o almeno diversamente da CL, Wolfram Alpha e altri. Come mai?

Uhmmm, sembra una cosa complessa. Intanto conviene partire da Wikipedia (come faremmo senza la Wiki? (auto-cit.)) che ci da la formula:

wkatnh

Sembra semplice. Però c’è scritto che vale solo per il dominio ]-1, 1[😦 E sì, logico: per x = 1 il denominatore della frazione si annulla😦 E per x < -1 la frazione ha valore negativo e il logaritmo…😦

Insomma non tanto semplice, anzi complessa😉

Ma, when the going gets tough, (cit.) Smettila, ti sbianchetto! sei ripetitivo!!!

C’è il Web, googlando spesso si trova, ecco:

, era una cosa complessa, cioè semplice ma bisognava usare i numeri complessi😀
Nota per qualcuno: sì lo so che dal post precedente era chiarissimo ma se non facevo un po’ di manfrina questo post sarebbe stato troppo breve e poi i grafici della funzione nel piano complesso mi sembrano molto interessanti, io da solo non ci sarei riuscito.
Nota perso incubosa: meno male che ho già passato gli esami di mate & dintorni, pensa se a un prof di cattivo umore viene in mente di chiederti qual è il dominio di arctanh(z). Prof, dai, lo so che (forse) sono paranoie ma …🙄

OK, tutto ciò premesso Racket va alla grande:

h0

proprio come dicono gli altri nel post citato precedentemente.

Perso (sì, lo so, si dovrebbe dire personalmente, me l’hanno fatto notare e sono anche stato sgridato, ma è un adattamento dal français, prendetevela con il mio ‘mico J-C o immaginate che ci sia l’accento sulla O) trovo lo script elegantissimo, tanto da riprodurlo qui di seguito:

#lang racket

(define (atanh x)
  (if (= x 1)
    "+/- infinity"  
    (* 1/2 (log (/ (+ 1 x) (- 1 x))))))

La funzione si riduce a una sola riga, inserita in un test if per discriminare la condizione di infinito (non ho indagato per il segno, who cares?). Notare che i numeri per Racket (OK, per il Lisp) non sono quelli dei successori di Algol (e Fortran).

Si può fare con Python? Io sono noto come evangelista Python che per tante cose è ottimo e meriterebbe di più e allora devo dire sì, certo.

C’è solo da tener conto di una cosa: i numeri complessi, non ci sono di default, serve il modulo cmath, presente fin dall’installazione del linguaggio. Io uso (e raccomando) la versione 3.x ma è uguale a quello della versione precedente (che consiglio solo in caso di codice esistente o dipendente da moduli non disponibili per la 3, per esempio Wx).

Ecco:

#!/usr/bin/python3

import cmath

def atanh(x):
    if (x == 1):
        return "+/- infinity"
    else:
        return 0.5 * cmath.log ((1 + x) / (1 - x))
        
#test
x = 0
print(x, atanh(x))
x = 1
print(x, atanh(x))
x = 2
print(x, atanh(x))
x = -2
print(x, atanh(x))

h1

OK, ah! con riferimento al post precedente sull’argomento: Racket promosso summa cum laude, nèh. Ma –si sa– Racket rockz😀😉🙄:mrgreen:

Un quiz, soluzioni con Python e Racket

bach-origTrovare quel numero che diviso per 2 ha come resto 1, diviso per 3 ha sempre resto 1, e ugualmente diviso per 4, per 5 o per 6 ha sempre resto 1, ma se viene divso per sette dà resto zero.
Federico Peiretti, Il matematico si diverte, Longanesi 2010, p.83. riferito a Claude-Gaspard Bachet.

Diophantus-cover

Claude-Gaspard Bachet è un matemeatico (e non solo) importante, che giustifica l’uso del quiz molto semplice ma devo fare pratica; e poi c’era anche il mio amico GG (prossimamente, forse…).

Ancora una cosa: l’immagine iniziale è presa da Gallica, qui.

Sono anche in regola con le condizioni d’uso. E grazie Gallica e Bibliothèque nationale de France😀

Ah! il problema lo trovate a p.199 del libro originale corrispondente a p.218 del PDF.

OK, siccome sono niubbo provo prima con Python.
Occorre trovare quel numero divisibile per 7 che ha modulo 1 per il minimo comune multiplo di {2, 3, 4, 5, 6}. La funzione per il calcolo del minimo comune multiplo (lcm) l’ho copiata da Rosetta Code.

Quindi ecco, Python, cgb.py:

#/usr/bin/python3

def lcm(*values):
	values = set([abs(int(v)) for v in values])
	if values and 0 not in values:
		n = n0 = max(values)
		values.remove(n)
		while any( n % m for m in values ):
			n += n0
		return n
	return 0

#main
mcm = lcm(2, 3, 4, 5, 6)
found = False
n = 0
while not found:
	n += 1
	found = ((mcm * n + 1) % 7) == 0
print(mcm * n + 1)

py

E con Racket? bèh, qui sono ancora un po’ (tanto) niubbo ma insomma…

E poi c’è la reference in locale, comodissima:

doc

Sì, bash si lamenta di Firefox ma solo per far vedere che c’è anche lui…

Ma Racket? OK, ecco cgb.rkt:

#lang racket

(define mcm (lcm 2 3 4 5 6))
(define num
  (let cgb ([n 1])
    (if (positive? (modulo (add1 (* n mcm)) 7))
      (cgb (add1 n))
      (add1 (* n mcm)))))
(print num)
(newline)   

rkt
La funzione per il calcolo del minimo comune multiplo (lcm) è predefinita😀
Il codice è elementare, da niubbo, costruito traducendo quello di Python. Ho usato troppe variabili; ho ripetuto un calcolo numerico una volta più del necessario. Prometto solennemente che in futuro sarò più funzionale.
Giustificazioni: 1) sono niubbo; 2) stavo propagandando Racket a una possibile vittima; con 3) paura di fare una figuraccia.
Poi a demo fatta ho dimenticato il tutto per una settimana, quasi. Ma devo fare pratica, per questo lo pubblico anche se non ottimale:mrgreen:

Nota: corretto un erroraccio, avevo scritto “divisore” al posto di “multiplo”. Grazie a Roberto Giacomelli😀

Più di un hacker, un virtuoso: Peter Deutsch

lwAl solito tutto parte da un tweet, da uno che seguo e mi segue😀 Lisp World, questo.
replinvTweet eccezionale, l’immagine è fantastica, visto la bici? e il resto, certo. Però –forse– c’è un’esagerazione nel cinguettio: “Inventor of the Lisp REPL“.
Per i non lispers REPL sta per Read, Eval, Print, Loop. E la conoscono e usano in parecchi, non è necessario essere lispers. È la versione interattiva dei linguaggi, quella che trovate se scrivete python, python3, idle, sbcl --noinform, rlwrap sbcl --noinform, racket -il xrepl, gst, irb --simple-prompt, …
Non è che devo continuare vero? Perché se servisse ne avrei tanti altri. D’accordo loro non la chiamano REPL ma versione interattiva o qualcosa di simile ma è quella.

Tornando a Peter una googlata per immagini ha chiarito tutto parecchio.
Ecco: L. Peter Deutsch’s PIVOT program verification system.

OK, c’è tutto. E voi fate come volete ma Dusty Decks io lo RSSisco, anzi già fatto.

Però, ora che ci penso. Quando ero giovane anch’io facevo delle REPL, senza sapere che si chiamavano così e erano già state inventate (a me nessuno mi dice mai niente, e anche allora nessuno mi diceva mai niente e non c’era ancora il Web, anzi nemmeno i BBS). Perché fare una REPL non è difficile, la parola chiave è loop, un ciclo indefinito. Con il Fortran si faceva con un GOTO che ti rimandava all’inizio del codice. Il mio collega e amico (più amico che collega) Giorgio aveva riscritto l’editor ED del Prime in GW-Basic (mancava solo il comando gmodify ma tanto quello non lo usava nessuno).

Anzi, sapete che vi dico?
Mi viene voglia di crearne una, un abbozzo, uso Python 3.x anche se … OK, meno conosciuto di Python e io sono un evangelista di Python da sempre, ecco:

Prima versione semplicissima:

#!/usr/bin/python3

while True:
    st = input('-> ')
    print(eval(st))

r0ma …

r1

Bisogna gestire le eccezioni …

#!/usr/bin/python3

while True:
        st = input('-> ')
        try:
                print(eval(st))
        except Exception:
                pass

r2ancora …

#!/usr/bin/python3

stprec = ''
diz ={}
while True:
    st = input('-> ')
    peq = st.find('=')
    print(st, peq)
    try:
        if st == 'st':
            st = stprec
        elif peg >= 0:
            key_ = str(st[:peg].strip())
            dat_ = st[peg:].strip()
            diz[key_] = dat_
        else:
            print(eval(st))
    except Exception:
        pass
    stprec = st

r3e poi

#!/usr/bin/python3

stprec = ''
peg = -1
diz = dict()
while True:
    st = input('-> ')
    if st == 'quit' : quit()
    peg = st.find('=')
    if st == 'st':
        st = stprec
    elif peg >= 0:
        key_ = st[:peg].strip()
        dat_ = st[peg + 1:].strip()
        diz[key_] =dat_
    else:
        try:
            if st in diz:
                st = diz[st]
            print(eval(st))
        except:
            pass
    stprec = st

r4
E si potrebbe continuare, volendo, questo…

:mrgreen:

Functional Programming in Python di David Mertz

1500C’è chi dice che venerdì 17, la versione nazionale del più qualificato e universale venerdì 13 porti spheega. Ma forse no, se non ci credi.

Prendi per esempio l’ultimo, quello di luglio dove è saltato fuori un tweet on writing shorter & less bug-prone Python code, questo.

David è un cubano di San Francisco (quella della Bay Area, certo, in cima a Silicon Valley) che si autodefinisce an ideational bricoleur.  Su Twitter non è che è molto attivo, ma se continua e s’impegna lo followerò, promesso.

Per intanto il malloppo (no, dai sintetico 49 pagine in tutto comprese copertine, legalesismi e simili) moolto accattivante. Roba che mi viene voglia di farne un riassunto, chissà che non riesca a invogliarvi al linguaggio e al modo di codificare funzionalmente.

Parte subito con la definizione di programmazione funzionale (FP) in modo sensato, io non avrei saputo far meglio😆

Personally, I would roughly characterize functional programming as
having at least several of the following characteristics. Languages
that get called functional make these things easy, and make other
things either hard or impossible:

  • Functions are first class (objects). That is, everything you can do with “data” can be done with functions themselves (such as passing a function to another function).
  • Recursion is used as a primary control structure. In some languages, no other “loop” construct exists.
  • There is a focus on list processing (for example, it is the source of the name Lisp). Lists are often used with recursion on sublists as a substitute for loops.
    “Pure” functional languages eschew side effects. This excludes the almost ubiquitous pattern in imperative languages of assigning first one, then another value to the same variable to track the program state.
  • Functional programming either discourages or outright disallows statements, and instead works with the evaluation of expressions (in other words, functions plus arguments). In the pure case, one program is one expression (plus supporting definitions).
  • Functional programming worries about what is to be computed rather than how it is to be computed.
  • Much functional programming utilizes “higher order” functions (in other words, functions that operate on functions that operate on functions).

Naturalmente il grado di FP varia, i puristi forse esagerano e comunque Python is most definitely not a “pure functional programming language”; side effects are widespread in most Python programs. That
is, variables are frequently rebound, mutable data collections often
change contents, and I/O is freely interleaved with computation. It is
also not even a “functional programming language” more generally.
However, Python is a multiparadigm language that makes functional
programming easy to do when desired, and easy to mix with other
programming styles.

Ma per chi non è un purista estremista (dai io vengo (nel senso che ho cominciato) dal Fortran per dire!) e allora …😀

David ci introduce a Multiple Dispatch di Matthew Rocklin, credo di averla già indicata, se no lo faccio adesso, come the best current implementation of the concept it implements.

Adesso andate a leggere di là ma prima vorrei farvi notare che certe licenze ortografiche che uso non sono mie, p.es. pyrsisten, toolz et al.

Poi una ciliegia tira l’altra e in men che non si dica ci troviamo in Charming Python (no, non metto il link, è di là).

Tutto questo nella prefazione, in attesa del primo capitolo con un titolo non meno astoundingcente: (Avoiding) Flow Control. Forse sapete già da come ho cominciato, e qui vi confesso che sono contento che ero seduto quando l’ho visto😉

Qui si illustrano i costrutti tipici di FP, con esempi, quali l’encapsulation, la comprehension, la ricorsione, come eliminare i cicli (loops) con la funzione map().
Anche la ricorsione si può a volte fare senza ricorsione, p.es. con reduce().

Il capitolo 2, Callables passa in rassegna i diversi modi di chiamata di funzione (con Python), ci sono le lambda, i @decoratori, le closures e altre bestie che voi imperativi… Ma che diventano presto cose sensate e indispensabili.

Siamo così pronti alla Lazy Evaluation, fare solo quando serve, proprio come Haskell (e me).

Qui per non non haskellisti c’è da masterizzare un po’ di cose nuove, here is a quick example of combining a few things. Rather than the stateful Fibonacci class to let us keep a running sum, we might simply create a single lazy iterator to generate both the current number and this sum:

def fibonacci():
    a, b = 1, 1
    while True:
        yield a
        a, b = b, a + b

from itertools import tee, accumulate
s, t = tee(fibonacci())
pairs = zip(t, accumulate(s))
for _, (fib, total) in zip(range(7), pairs):
    print(fib, total)

fp-fib

Figuring out exactly how to use functions in itertools correctly and optimally often requires careful thought, but once combined, remarkable power is obtained for dealing with large, or even infinite, iterators that could not be done with concrete collections.

The documentation for the itertools module contain details on its combinatorial functions as well as a number of short recipes for combining them.

Tutto da assimilare, diverse funzioni che devono diventare abituali :grin.

E adesso siamo pronti per le Higher-Order Functions (HOFs). In general, a higher-order function is simply a function that takes one or more functions as arguments and/or produces a function as a result. Many interesting abstractions are available here. They allow chaining and combining higher-order functions in a manner analogous to how we can combine functions in itertools to produce new iterables.

E si finisce con i @decorators, ecco questi per me sono ancora un po’ nuovi; ma ci sto lavorando, nèh!

Intanto il book finisce con indicazioni più sensate su David, rockz!

:mrgreen:

Spyder, un IDE per Python

Spyder_logo

Sapete la serendipity, ricorsiva in questo caso. Recentemente un giovane volonteroso mi chiedeva quale IDE semplice usare per impratichirsi con Python. Io, dopo avergli ricordato che essedo vecchio uso un editor normale (Gedit, sì lo so che c’è di meglio) ho consigliato Geany. Che ogni tanto uso anch’io. E sì, c’è anche per Windows, cosa che in quel caso era necessaria.
Giovedì pomeriggio mi viene ripetuta la stessa richiesta. E io insisto con Geany.

E adesso chi glielo dice ai due? Sì perché ho trovato di meglio, grazie a un post che raccomanda Emacs: Emacs for Data Science.

Ma non voglio propagandare Emacs. Anche se è il migliore in assoluto, senza paragoni. Solo che per imparare a usarlo e sfruttare le sue possibilità ci vuole tempo e costanza e poi forse per le cose piccole non è necessario🙄 (Dai non infierite, a volte lo uso, per esempio con SLIME).

Spyder (formerly Pydee) is an open source cross-platform IDE for scientific programming in the Python language. Spyder integrates NumPy, SciPy, Matplotlib and IPython, as well as other open source software, dice la Wiki.

Una rapida occhiata alla pagina degli screenshots mi ha convinto a provarlo.

Per Ubuntu c’è nel Software Center, installo (per la versione 2.x ma c’è anche per la 3), 51 MB, ed ecco:

click per ingrandire

click per ingrandire

Nel terminale (ma non sono più obbligato a usarlo, cosa che genera lamentele per i windowsiani) ottengo:

con-fib

OK, l’esempio è semplicissimo, questo è il codice (fib.py):

# -*- coding: utf-8 -*-

def fibGen(n, a=0, b=1):
    print a, b,
    while n > 0:
        yield a
        a, b, n = b, a+b, n - 1
        print b,
        if (n % 5) == 0: print
#main
[i for i in fibGen(50)]

Ovviamente c’è molto di più, conviene leggere la documentazione, qui: Spyder – Documentation.
Il sito di Spyder è su GitHub.
E sì, dice come installarlo su Windows😀

Il problema dell’ora con Python

lazare-clocksUn post di Julien Danjou, Timezones and Python risolve forse, o forse no…
Julien la sa lunga su tante cose, guarda qui.

Recently, I’ve been fighting with the never ending issue of timezones

D’ho, me too! più volte; chissà se oggi si arriva a a qualcosa di utile?

tz0
Ecco, a cosa si riferisce? UTC o locale? Perso.
Julien riporta che Armin Ronacher dice di considerare gli oggetti datetime non specificati diversamente sempre come UTC; è la soluzione che avevo adottato anch’io.
Ma Julien va oltre, forse, vediamo.
Raccomanda di usare sempre oggetti datetime completi di informazione timezone. Per questo c’è pytz.
Inoltre usare il formato ISO8601 sia in input che output.

tz1

OOPS!😳 pytz mi manca!

provo a installarlo! ATZ! solo per Python 2.7.x, OK, tanto vale fino al 2020.

Devo installare easy_install con

sudo apt-get install python-setuptools

e quindi pytz

sudo easy_install --upgrade pytz

ed ecco:

tz2

Adesso manca iso8601, installo con

sudo easy_install iso8601

tz3

Però non finisce qui; la documentazione di pytz riporta cose interessanti.

The preferred way of dealing with times is to always work in UTC, converting to localtime only when generating output to be read by humans.

Ed è un pasticcio, proprio come quello che avevo fatto io, senza pytz, bocciato👿

Ci sono però parecchie cose, forse anche quello che serve:

tz4

Ma forse no. E se… sì Stack Overflow😀
Risulta che si può, ma è tutt’altro che facile, non so nemmeno se mettere il link. Lo metto solo per i più avventurosi, qui: Converting datetime.date to UTC timestamp in Python.

Quindi:

  • Python correggi altrimenti lo dico in giro;
  • Usare sempre UTC se avete a che fare con gente lontana, mettendo l’offset a UTC. Pensa te che per certe zone (India, parte del Canada) si va a mezz’ore.

Intanto Ok, panico:mrgreen:

Lisp – cl-launch – 1

1200x400Continuo da (indovina?) qui: Lisp – cl-launch – 0.
Sì ho problemi di titolazione, ma ci sto lavorando, prossimamente… forse…😉

Sono sempre alle prese con cl-launch, voglio provare con un esempio pratico. Pensa che ti ripensa mi è venuto di pensare che potrebbe essere una bella pensata la sequenza di Leonardo Pisano, Fibonacci per gli amici.

Adesso se uno volesse fare le cose per bene seguirebbe François-René, Faré. Questo è come la racconta lui.
Panico👿

OK, a frequentare i nerd non ti capita mai e poi mai (assolutamente mai) di trovarti nella stanza sbagliata (che sarebbe poi quella dove il più nerd sei tu). Vista così va meglio e mi da la forza di continuare.

La mia versione è decisamente più realistica:

(defvar n)
(defun fib (x &optional (y 0) (z 1))
   (if (< x z)
     nil
     (append (list z) (fib x z (+ y z)))))

(defun start (n)
   (format t "~a~%" (fib n)))

che gira così:

cl9

Con qualche piccola aggiunta diventa la versione per cl-launch:

#!/usr/bin/cl --entry start
(defvar n)
(defun fib (x &optional (y 0) (z 1))
   (if (< x z)
     nil
     (append (list z) (fib x z (+ y z)))))

(defun start (argv)
   (setf n (parse-integer (car argv)))
   (format t "~a~%" (fib n)))

Notare la shebang con l’opzione --entry e la variabile speciale argv. argv è una lista di stringhe (si vede nel post precedente) per cui devo fare un cast e –pensa te!– mi è venuto car invece di first (chi va con lo zoppo il nerd…).

cl10

Ahemmm… no👿
Si deve abilitare (stavo per scrivere chmodare ma poi Sergio…):

cl11

OK😀

Ho provato anche a creare l’immagine ma ottengo un errore, eventualmente una cosa per il futuro. Ho anche installato Quicklisp, dal suo sito.

Da parecchio tempo ormai sono conosciuto come pythonista. Anzi agli albori del blog gli amici blogger (quasi tutti passati a cose diverse, più serie, remunerative) mi avevano anche affibbiato un cognome subclassando dal Guido, m’è rimasto (con problemi di pronuncia: van si dice fan e Juhan Giu-an, nèh). Allora da pythonista mi viene da scrivere:

#!/usr/bin/python3
import sys

lim = int(sys.argv[1])
a, b = 1, 1
fib = [a, b]
while b < lim:
	a, b = b, a + b
	fib.append(b)
fib.pop(-1)
print(fib)

cl12

Ecco, non so se sono solo io ma mi viene da ragionare in modo differente. E se per il Lisp posso essere ripreso per aver usato una variabile globale –sarebbe bastato un let— qui la lista viene troppo lunga e devo rimuovere l’ultimo elemento😳 Sì, si può fare di meglio in entrambi i casi ma ho messo quello che mi è venuto in mente al volo.

cl13

Un confronto impietoso. Facendo la media tra 7 run, eliminando i casi migliore e peggiore, è risultato che il tempo richiesto da cl-launch è 14 volte quello richiesto da Python 3.
E, a rincarare le cose anche la RAM, guarda qua (tre lanci in rapida sequenza):

cpu

Faré ne parla, purtroppo la documentazione è dispersa e non sempre lineare, vedi il link sopra.

Continua, forse… anche perché OOPS!😳 non posso ancora dirlo:mrgreen:

Programmazione funzionale – si può fare con Python?

bbOK, forse non è l’attrezzo migliore ma vorrei affrontare l’argomento un po’ alla larga. E questo è solo l’inizio. Probabilmente continuerò per questo argomento — forse, chissà😉:mrgreen:

Per un caso di pura serendipity trovo questa definizione:

Functional programming (FP) is based on a simple premise with far-reaching implications: we construct our programs using only pure functions—in other words, functions that have no side effects. What are side effects? A function has a side effect if it does something other than simply return a result, for example:

  • Modifying a variable;
  • Modifying a data structure in place;
  • Setting a field on an object;
  • Throwing an exception or halting with an error;
  • Printing to the console or reading user input;
  • Reading from or writing to a file;
  • Drawing on the screen.

È l’inizio di Functional Programming in Scala di Paul Chiusano e Rúnar Bjarnason — grazie a Luis Souto Graña che me l’ha segnalato😀
Ecco messo in questi termini non è che si può andare molto lontano. Ma se invece ammettiamo che non tutte le funzioni siano pure forse qualcosa si può fare.

Una richiesta in proposito su Stack Overflow è stata chiusa da tutto un gruppo di amministratori: We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion.

Questa query functional programming in python dimostra un caso pratico. Ma Python per queste cose si dimostra particolarmente inefficiente.

f0E poi un pythonista userebbe probabilmente la list comprehension:

f1Seguono poi un paio (abbondante) di discussioni chiuse per vari motivi. E anche questa richiesta How to construct such a functional-programming tool in Python? molto specifica, imho, ha un paio di risposte pythoniche non semplicissime, anzi👿

La mia preferita è questa: Why program functionally in Python?
Anche perché Paul, fa ha la mia questione:  I understand that functional languages are good for concurrency but does programming Python functionally really help with concurrency?
La risposta più quotata, di Alex, è lunga e non riassumibile. E mi sembra che non sia tanto positiva. Io sono per beardedprojamz (la terza): I have to say that too much ‘bandwagoning’ toward OO or functional could lead toward missing elegant solutions.

Ecco, adesso il post sembra ridursi a poca cosa, molto meno di quello che lascia intravedere il titolo. Colpa mia lo ammetto. Ma concludo lo stesso con come la penso, una cosa scontata.
Se rileggo la definizione riportata all’inizio e mi accontento di cose possibili di quelle che riesco a fare anch’io posso arrivare al compromesso di avere funzioni FP (ecco, qui avrei dovuto dire funzioni funzionali) dove possibile, che fanno una sola cosa, senza effetti collaterali, non usano variabili globali (OK, è lo stesso di prima ma così mi capisco), in modo possibilmente efficiente. E che sono facili da capire dagli umani (pensate alla manutenzione). Anche quelli come me che arrivano solo fino a un certo punto (sapete ho cominciato con il Fortran (ma non ditelo a EWD)).

catAl di là di questo ambito non mi sembra che Python sia usabile. O sbaglio?:mrgreen:

Aggiornamento: sono stato precipitoso e pasticcione (assay!). Mi sono dimenticato che avevo materiaale qui nel blog (roba del prof Lipari (rockz)), è passato un po’ di tempo e poi –OK, niente scuse😳😥👿
Ecco un paio di link:

Poi forse continuo, tentando di rimediare:mrgreen:

Iscriviti

Ricevi al tuo indirizzo email tutti i nuovi post del sito.

Segui assieme ad altri 89 follower