Archivi Categorie: Linguaggi

Linguaggi di programmazione

Julia 1.0

The much anticipated 1.0 release of Julia is the culmination of nearly a decade of work to build a language for greedy programmers. JuliaCon2018 celebrated the event with a reception where the community officially set the version to 1.0.0 together.

Come si diceva all’inizio, nel 2012: We want a language that’s open source, with a liberal license. We want the speed of C with the dynamism of Ruby. We want a language that’s homoiconic, with true macros like Lisp, but with obvious, familiar mathematical notation like Matlab. We want something as usable for general programming as Python, as easy for statistics as R, as natural for string processing as Perl, as powerful for linear algebra as Matlab, as good at gluing programs together as the shell. Something that is dirt simple to learn, yet keeps the most serious hackers happy. We want it interactive and we want it compiled.

Ora c’è finalmente la versione 1-punto. Io ho perlustrato una versione precedente, già buona ma non ancora come questa. E ripeto la mia previsione che Julia sarà uno dei linguaggi del fururo. Anzi, fin da subito è da considerare in alternativa o complementariamente a Python, Octave (Matlab per i ricchi o quelli che devono fare cose davvero speciali), C++, altri (tanti altri).

Julia è speciale, dall’intro: Scientific computing has traditionally required the highest performance, yet domain experts have largely moved to slower dynamic languages for daily work. We believe there are many good reasons to prefer dynamic languages for these applications, and we do not expect their use to diminish. Fortunately, modern language design and compiler techniques make it possible to mostly eliminate the performance trade-off and provide a single environment productive enough for prototyping and efficient enough for deploying performance-intensive applications. The Julia programming language fills this role: it is a flexible dynamic language, appropriate for scientific and numerical computing, with performance comparable to traditional statically-typed languages.

Il team di sviluppo rockz, davvero, anzi über 💥, guarda qui la Wiki. E, ovviamente, il sito di Julia.

Ah! adesso qualcosa di completamente differente, in qualche misura complementare: ci sono altre novità, per altri linguaggi:

Python non si ferma mai, c’è la versione 3.7, con novità (l’evoluzione) che personalmente devo ancora approfondire.


Racket ha fatto un grande balzo, c’è la versione 7.0 ancora migliorata (mica facile ma sì, davvero).


Aggiornamento
Ahemmm… Julia non è ancora così a posto come vorrebbe (vorrei, vorremmo tutti). guarda qua: Think Julia: How to Think Like a Computer Scientist.
Ma crescerà, ricordiamoci sempre che Ankh-Morpork non è stata costruita in un giorno.

Un quiz & considerazioni personali relative

Cosa non si trova ontehtoobz! (auto-cit.) 😯 Ieri questo: I was just shown this. Guess what this does in Python? powers = [lambda x: x**i for i in range(10)] powers[3](2).

Sukant è conosciuto, in diversi socials, rockz. E, confesso, ho provato a risolvere il suo quiz, nel senso di correggere la funzione, senza riuscirci. Poi ho letto i commenti, già David A Roberts 💥 doveva mettermi sulla retta via:

* quiz $ py3
>>> def f(i): return lambda x: x**i
...
>>> powers = [f(i) for i in range(10)]
>>> powers[3](2)
8

ma ci sono altri come me che non sono così pronti: How is it Alex Jones got banned, and yet Sukant still has a twitter account after posting this?? dice Warner e Leftmost Grief Node: Haha the Pythonistas responding to this in my org are like, “Well that code is not Pythonic so…”.

das portal ci spiega il perché, Dan P ci dice che Scala…

Ma la risposta migliore è quella di jeeger che si potrebbe tradurre con *RTFM!*, in questo caso The Hitchhiker’s Guide to Python, in particolare –chiaro come il sole– Late Binding Closures.

Non copio è là.
Da leggere attentamente, anzi studiare che poi interrogo, nèh! 🧐

Ci ho pensato su. Anzi ci ho dormito su. E ho maturato una mia opinione che potrò cambiare se e solo se fatti o circostanze me lo consiglieranno.

In questo caso –e tanti altri casi simili– il problema non esiste:

>>> pow(2, 3)
8
>>> pow(2, 0.5)
1.4142135623730951
>>> pow(-2, 0.5)
(8.659560562354934e-17+1.4142135623730951j)

Non ce l’ho con lambda e le funzioni e quant’altro ma con il loro (ab)uso. E usare solo quello che si conosce davvero. Detto in altri termini non ho ancora digerito il fatto che non ho trovato il bug 👿

Comunque…

Siate semplici (cit.). Anzi, qui. È talmente autoevidente che non si sa di chi è; è Patrimonio dell’Umanità (se non lo è dovrebbe esserlo).

Formattare le stringhe in Python

Python lo uso da sempre (cioè no, ho solo dimenticato quando l’ho scoperto (o meglio il numero della versione che mi sembra di ricordar è troppo basso per essere credibile) e capita che ogni tanto scopro di non essere aggiornato, sapete l’evilussione 🧐 Per fortuna c’è Twitter che mi suggerisce, via prof Corno ecco: Python 3’s f-Strings: An Improved String Formatting Syntax (Guide).

La documentazione ufficiale corrente di Python (3.6 o mi sto perdendo qualcosa anche qui? sì. c’è la 3.7 nuova di pakka, non ancora installata) è aggiornata e dice tutto, anche se in modo un po’ troppo sintetico per quelli come me.

A formatted string literal or f-string is a string literal that is prefixed with ‘f‘ or ‘F‘.

Conviene quindi seguire la guida di RealPython, anzi RealPython è da followare su Twitter, fatto.

Anzi, la guida è talmente OK che non continuo a scrivere, c’è tutto là. A me resterebbe di aggiornare gazillioni di script che usano non immaginate cosa (l’evilussione) ma poi mi viene da pensare che (cit.)

anche perché capita troppo spesso che parto con l’idea di aggiornare e mi scopro a riscrivere ⭕

La funzione è …

Un thread su Twitter mi fa monta la voglia di dire la mia. E so resistere a tante cose ma non alle tentazioni (quasi-cit.) e allora ecco questo post senza pretese. Anzi forse nemmeno da leggere.

Tutto parte da qui: a function is sort of a container for bugs.

Siccome il post è mio dico subito la mia risposta: la funzione è un valore, esempio:

Ma anticamente la risposta sarebbe stata diversa. Qualcosa come: una funzione è un sottoprogramma che ritorna un valore; nella pratica si preferisce usare le subroutines, forse solo per convenzione.

Sì, erano i tempi in cui si usava il Fortran (l’unico (quasi) linguaggio disponibile su quel ‘puter). Volevo riportare un esempio di allora, ho lanciato bigG ed ecco:

sono soddisfazioni, se lo fate voi che avete interessi migliori probabilmente la risposta è diversa; in ogni caso mi dice solo che è una memoria indelebile per me. E forse per altri. Forse non solo la T$AMLC (se interessa: gestione comunicazioni con periferiche seriali). Esiste un sito storico, Bitsavers, con tanti documenti storici ma non ho trovato quel che cercavo.

Erano una cosa molto diversa da cosa si scrive oggi; invece di raccontarlo vi rimando a questa pagina: Functions and Subroutines.

Bella ma incompleta. Segue le prescrizioni del Fortran IV (1966). Non dice chiaramente che in Fortran tutti i dati sono passati per indirizzo e se vengono (o meglio venivano, oggi le cose sono migliorate, vedi p.es. qui) modificati all’interno del sottoprogramma (funzione o subroutine) risulteranno modificati al ritorno dalla chiamata. E manca di ricordarci del COMMON, allora pervasivo per quello che sarebbero diventate le variabili globali, anzi più specifico, migliore (anche nella creazione di bugs difficili da stanare).
Nella pratica poi le variabili venivano dichiarate solo se di tipo diverso da quello implicito (era anzi considerata una prassi da evitare non seguire la convenzione implicita).

OK, fine della premessa; torno al tweet. Ron dice “ma il BASIC…”. Vero. Anzi anche peggio. Il GOSUB era facoltativo, sostituibile con GOTO, ma dovevi accordarti con RETURN. Poi il linguaggio è migliorato notevolmente, solo i vecchi si ricordano di questo e ci twittano.

Algol fin da allora distingueva valori e indirizzi nei parametri. Poi è arrivato il C, dove ci sono solo le funzioni. Ma possono restituire null. E sono puntatori.

Haskell invece –uh! post troppo lungo ⭕

Perché il ciclo for di Python è speciale

Il titolo avrebbe dovuto essere “perché range(start, end) non comprende end?” ma si sarebbe perso il riferimento a for.

Forse lo sanno tutti, forse qualcuno l’ha scoperto da poco, altri ancora forse no. E perché?  Sto dicendo del ciclo for in Python.

Nella riscrittura di in Python di un programmino Basic c’è stata un po’ di confusione sugli indici di arrays e contatori di cicli.

Utilizzo MY-BASIC di Wang Renxin per visualizzare il ciclo for come lo intende il Basic, in tutte le sue varianti e incarnazioni, in particolare nel mio caso si tratta di VB, Visual Basic.

run e bye sono estensioni di MY-BASIC, il comando mb invece è un alias mio ma l’esempio –minimo– illustra come il Basic gestisce il ciclo, in particolare il ciclo comprende il limite finale, 5 in questo caso. Lo stesso comportamento lo troviamo nel linguaggio da cui il Basic deriva, il Fortran (dove il ciclo si chiama do). L’istruzione può prevedere un passo per l’indice, così:

OK? Ma questa è un’eccezione, dal C in poi il ciclo for ha una sintassi diversa, per esempio con nodejs (un sapore di JavaScript) posso scrivere:

Ovviamente si può scrivere <= al posto di < comprendendo così il limite superiore. Con C e C++ la sintassi è la stessa, migliora solo l’istruzione di scrittura, printf() e/o cout <<.

Il for per Python è diverso, funziona con le liste:

Potrei usare una lista di numeri:

Per creare una lista di numeri, come quelle che si trovano di solito nei cicli for esiste la funzione range().

The range type represents an immutable sequence of numbers and is commonly used for looping a specific number of times in for loops.

Come si vede il limite finale non è mai compreso. Per cui il ciclo iniziale (quello dei numeri da 1 a 5) sarà:

Visto 6 e non 5.

C’è un potivo per tutto ciò, il BDFL (emerito da due giorni) Guido la sa lunga:

in questo modo la lunghezza (len()) della lista è uguale al limite superiore del range(). Altre cosa da ricordare (già usata implicitamente ma è bene ricordarla per quelli come me che vengono dal Fortran) è che gli indici partono da 0, zero.

Questo è spiegato più in dettaglio qui.

E per chi vuole saperne di più passo la parola a EDW, qui: Why numbering should start at zero.

Grazie Guido 💥

Ieri Guido van Rossum ha comunicato che non farà più il capo di tutti i pythonisti. La speranza è che continui a seguire, anche se non al timone, rockz! 💥 assay 👽‼️

End of an era! Thanks for everything you did, @gvanrossum, it was an honor collaborating with you. Let’s hope the Python projects finds a way to govern itself effectively. A no-BDFL model is working for other porjects, hopefully it will for this one to.

La rassegna delle prime reazioni, altre seguiranno senz’altro, e –come dicono a Piobes (pron. piubes)– tomorrow is another day! e the show must go on ma assolutamente non frankly my dear, I don’t give a damn .

Transfer of pywer.

Armin Ronacher’s Thoughts.
il titolo migliore, imho.

As you can tell from my online nickname, python means a lot to me.

Wow, big news. Guido van Rossum is stepping down from leading Python development.

Python Language Founder Steps Down.

I’m sorry, I’m not allowed to argue any more.

Thanks for all the support (email and Twitter).

Running a community around a big open source project can be a thankless job. If you use open source tools, make sure you appreciate the maintainers who make it possible.

I don’t ever want to have to fight so hard for a PEP and find that so many people despise my decisions.

The PSF and Pythonistas everywhere are deeply grateful for all he has done creating Python and guiding it for so long.

Grateful for Guido van Rossum @gvanrossum’s leadership of Python, which has changed AI and software engineering.

Python is the reason I started programming.

Elimina le righe duplicate, ma tieni le vuote

È fattibile uno script che dato un file di testo faccia come da titolo? Uh! vediamo 😯

Un compito semplice e conosciutissimo –anche da me– esegue la prima parte, eccolo:

#!/usr/bin/awk -f

!a[$0]++

Funziona perfettamente, esempio:

Proprio OK, eliminate tutte le doppie.
Ma a me servirebbe un’altra cosa: le righe vuote voglio tenerle tutte. Questo mi serve per le raccolte di Visto nel Web, AI e innovazioni e cit. e loll. dove le righe vuote separano le descrizioni dei link. OK, dovrei riscrivere tutto ma adesso va di moda –funzionalmente– essere lazy… 😉

AWK è uno dei miei linguaggi preferiti da sempre; appena misi le mani su un ‘puter Unix feci le fotocopie dei manuali di sh, vi, sed e AWK. Per Fortran e C avevo già tutto, cioè no, qualcosa: il K&R troppo sintetico, il TAB da aggiustare per il Fortran, le opzioni di compilazione, mica c’era Stak Overflow allora 😐 E neanche il Web. E anche i BBS sarebbero venuti dopo (con l’accoppiatore acustico (modem) a 2400 BPS). OK, sono OT 😐

Non so se la soluzione cui sono giunto sia bella, ma mi sembra funzioni e per adesso è questa (ndtv0):

#!/usr/bin/awk -f

{ if  ($1 ~ /^\#:/ || $0 == "")
  { print }
  else
  { { if (!a[$0]++) print }
  }
}

A dirla tutta c’è una riga vuota di troppo ma questo non da fastidio al mio caso. Questo però è solo il primo passo. Devo salvare l’output in un file e confrontarlo con quello di input. Se i due coincidono lo cancello altrimenti cancello l’originale (no, lo rinomino con estensione .bak) e rimonimo l’output con il nome dell’originale (file ndtv1).

#!/bin/bash

ndtv0 $1 > $1".tmp"
diff -s $1 $1".tmp"
R=$?
if [ $R == 1 ]; then
  echo "aggiorno"
  mv $1 $1".bak"
  mv $1".tmp" $1
else
  rm $1".tmp"
fi

Ripetendo il comando il file dovrebbe già essere OK:

OK, non resta che abilitare ndtv0 e ndtv1 (dopo averlo spostato in ~/bin o in un’altra dir presente in $PATH).

Ma è una cosa tutt’altro che finita. Nello script AWK ho inserito di tenere le righe delle categorie, quelle che iniziano con #: (notare che # è speciale e dev’essere baskslashato).

Il file risultante da questo filtro potrà risultare con righe fuori posto, come le due righe vuote consecutive dell’esempio. Ma qui continuo con un linguaggio normale (Python in questo caso) e il lavoro diventa più normale, noioso. Un collega di una volta (quasi 30 anni fa) dissente dal mio insistere con roba tipo AWK. Sono vecchio (ma anche lui, anagraficamente). Forse è arrivata per me l’ora di smettere, anche perché i blog sono passati di moda 😐

e, pi, una volta e adesso

Dave ci ricorda che approfittando delle feste –OK, leggete qui.

Io non solo non ho partecipato, neanche commentato. A dire il vero non avrei potuto, non c’ero ancora. Ma rimedio subito.

Oggi è facilissimo, viene aggratiss, per esempio con bc:

Le ultime 2 cifre possono essere non precise per problemi di arrotondamento, se del caso basta aumentare il numero di cifre richieste, attraverso la varialibe scale. Non ci sono problemi, l’hardware non è quello di Von Neumann, per esempio per 4000 cifre uso lo script pi.bc:

scale=4000
pi=4*a(1)
print pi
print "\n"
quit

e è nella funzione e(), avendo visto che la precisione non è un problema uso quella di default (20 cifre caricando la libreria matematica con -l)

Con Python basta installare uno dei moduli per la precisione arbitraria. Anzi probabilmente non è necessario se si usa SciPy/NumPy &co ma oggi un modo alternativo, più sexy, via mpmath installabile con pip3 install mpmath. seguendo le dritte di Fredrik Johansson qui, 100 mpmath one-liners for pi ecco:

OK, è una collaborazione, largo ai giovani!

Sostituire i TABs e i caratteri non-ASCII

A volte il testo preso dal Web o da altri posti ancora non è come lo vorremmo. Capita che contenga caratteri strani, per esempio TABs, caratteri Unicode (a volte sono OK, a volte no, per esempio nel codice apici e virgolette devono essere quelli classici anche se meno belli), λ (OK ma non nella REPL di Racket (sì, questo solo per me)). Ecco il terminale è uno di quelli che certe cose proprio non le accetta.

Vero che in (quasi) qualsiasi editor si può fare ma se del caso…

Comincio con TAB, serve come base poi generalizzabile (file stab):

#!/bin/bash

if [ -z $1 ]; then
  echo 'uso:' $0 '[sost-char] file'
  exit 2
elif [ -z $2 ]; then
  SOST=' '
  PROC=$1
else
  SOST=$1
  PROC=$2
fi

sed "s/\t/$SOST/g" $PROC

Lanciato senza opzioni esce con un messaggio:

È richiesto il nome del file preceduto opzionalmente con il carattere (o i caratteri) che sostituiranno il TAB.

OK? C’è (ancora, pare che adesso Windows 10 sia sulla buona strada) chi preferisce Python. Si può fare; anzi lo script risulta simile (stab.py):

#!/usr/bin/python3

import sys, re

if len(sys.argv) == 1:
  print ('uso:', sys.argv[0], '[sost-char] file')
  exit(2)
elif len(sys.argv) == 2:
  sost = ' '
  proc = sys.argv[1]
else:
  sost = sys.argv[1]
  proc = sys.argv[2]

with open(proc, 'r') as f:
  txt = f.readlines()

for st in txt:
  print(re.sub('\t', sost, st), end='')

È possibile evitare l’uso delle espressioni regolari (modulo re che ho preferito per uniformità con lo script seguente): basta sostiture l’ultimo ciclo for con

for st in txt:
  print(st.replace('\t', sost), end='')

Generalizzando arrivo ad andare alla ricerca di tutti i caratteri fuori dalla sequenza ASCII. Ho copiato in un file un paio di tweets (dimenticando di salvare il nome degli autori) contenenti citazioni quotate. Nel primo si usano le virgolette che si trovano nella stampa tedesca, nel secondo no, roba corrente ontehtoobz. Ho aggiunto un paio di emoji, ormai hanno invaso il Web. Poi passo a evidenziali:

Questo è lo script fuori.py:

#!/usr/bin/python3

import sys, re

if len(sys.argv) == 1:
  print ('uso:', sys.argv[0], '[sost-char] file')
  exit(2)
elif len(sys.argv) == 2:
  sost = '_'
  proc = sys.argv[1]
else:
  sost = sys.argv[1]
  proc = sys.argv[2]

with open(proc, 'r') as f:
  txt = f.readlines()

for st in txt:
  print(re.sub(r'[^\x00-\x7f]', sost, st), end='')

Procedo come per il TAB ma con sed ci sono problemi, dovuti alla tabella caratteri caricata se abbiamo capito bene. Ancora da indagare (e risolvere), materia per un prossimo post.

OK, 😁⭕

Globale o locale?

Jake 💥 rockz e oggi ci racconta di un caso che neanche Dirk Gentlyquesto.

Lo riscrivo con una piccola modifica (l’istruzione print per vedere il risultato), file e0.py:

def g(x):
  def f():
    x += 1
  f()

print(g(0))

Err! 😡, e come dice Jake: That was a fun one to explain 😀. Dico subito che da solo non ci sono arrivato; poi mi sono detto che dovevo pensarci ma…

Provo a fare come avrei dovuto. Invece di operare sulla variabile (globale) x nella f() ritorno il valore di x modificato, così (file e1.py):

def g(x):
  def f():
    return x + 1
  f()

print(g(0))

OOPS! per Python è OK ma non per me, correggo (e2.py):

def g(x):
  def f():
    return x + 1
  return f()

print(g(0))

Chiaro? Torno al tweet, nel thread c’è la dritta, il link a –indovina– la documentazione ufficiale di Python, qui: Why am I getting an UnboundLocalError when the variable has a value?

La spiegazione è diversa (più esaustiva) della mia, in sintesi:

This is because when you make an assignment to a variable in a scope, that variable becomes local to that scope and shadows any similarly named variable in the outer scope. Since the last statement in foo assigns a new value to x, the compiler recognizes it as a local variable. Consequently when the earlier print(x) attempts to print the uninitialized local variable and an error results.

Logico. E con certi linguaggi –nuovi, di moda– le variabili, quando ci sono, sono quelle, restano tali, niente modifiche. Per esempio Haskell –lasciato come esercizio. È da tanto che volevo dire questa frase 😊.

Invece in un’altra famiglia di linguaggi –sexy, i miei preferiti– non serve scrivere “return“, la funzione è un valore (file e3.rkt):

(define (g x)
  (define (f)
    (+ 1 x))
    (f))

(displayln (g 0))

Ma nessun lisper userebbe la funzione f(), viene chiamata una volta sola, per questo c’è lambda (e4.rkt):

(define (g x)
  ((lambda (t) (+ 1 t)) x))

(displayln (g 0))

Non mi piace, inutilmente contorta, basta (e5.rkt):

(define (g x)
  (+ 1 x))

(displayln (g 0))

Dove ho semplificato (troppo? f e g in un programma reale conterranno altre istruzioni) il codice. Ma era ridondante, lambda si usa quando serve.

Poi ci ho ripensato ancora (tutta la notte) e sono giunto a una conclusione che forse vale solo per me ma penso che il codice del tweet sia sbagliato come progettazione. Se x dev’essere globale si deve dichiarare, così (e6.py):

def g(x):
  def f():
    global x
    x += 1
  f()

# main
x = 0
g(0)
print(x)

Ovviamente il parametro in g() è inutile e dannoso come si scoprirà nel debug della prima revisione (e7.py):

def g(x):
  def f():
    global x
    x += 1
  f()

# main
x = 0
g(42) # <- ====
print(x)