Visto nel Web – 183

Uh! già domenica. E io che devo ancora finire –OK, smetto che devo dirvi cosa ho visto nel Web.

manifesto10
What’s New In Python 3.5
::: Python documentation

A Secular Shift To Online Food Ordering
::: TechCrunch

Le regole nell’evoluzione degli umani e dei robot
::: Luca De Biase

Inno del programmatore
::: Pinperepette

Programming is the art of telling…
::: pavelfatin

CE3EtW3XIAEv8Am

I think my favorite kind of programming is…
::: peterseibel

Scratch Day raccontanto con i tweet!
::: CoderDojo Padova

Manifesto Venetodigitale
::: Veneto Digitale

How To Set Up a Pirate EBook Store In Google Play Books
::: Slashdot

CoderDojo Voghera: di nuovo ScratchTastic!
::: Eventbrite

11206094_831161653630150_2173004976781436869_n

FCC Tosses Petition Challenging Its New Internet Regulations
::: Slashdot

La battaglia per essere liberi: perché i giornalisti devono essere attivisti
::: Valigia Blu

Tenete accesi i dischi SSD
::: SIAMO GEEK

Can quantum computing change the world? This start-up is betting on it
::: Washington Post

Come la nuova fotografia sta cambiando noi e gli oggetti di uso quotidiano
::: Giuseppe Granieri

11223750_10152702666016396_1620195423471582931_n

Self-Driving Cars In California: 4 Out of 48 Have Accidents, None Their Fault
umani siete domati :wink:
::: Slashdot

64% of Americans now own smartphones
::: pewinternet

@WikiLeaks releases 10 months of transcripts from German parliamentary inquiry into the NSA
::: wikileaks

Big Data Can Reshape The World And Save Lives [Infographic]
::: The Hague Declaration

Criticizing the Rust Language, and Why C/C++ Will Never Die
::: Slashdot

charlie

How To Install Alarm Clock in Ubuntu 15.04
::: Ubuntubuzz

Under the hood: Facebook’s cold storage system
(ahemmm, no, non l’ho letto (ancora))
::: Facebook

Introducing Instant Articles
::: Facebook ::: Downloadblog

È sempre su internet? Dipende!
::: Sergio Gridelli

11073819_940752522630960_8244632107389568260_n

L’ultima follia di Cameron: niente tweet senza approvazione preventiva della polizia
::: Wired

I PPA di Debian non funzioneranno su Ubuntu e viceversa
perché?
::: oneOpenSource

House approves NSA reform
::: Engadget ::: Washington Post

A processo per un commento su Facebook – Ora il giudice deve decidere se è diffamazione
::: L’Espresso

Lanciatore Conky ON/OFF
semplice ma OK, bravo Rosario :grin:
::: SalentOS

Anna Fugale

Ecco chi lavora nella sorveglianza di massa
::: Wired

Facebook si sta mangiando Internet
::: Studio

Baidu’s Supercomputer Beats Google At Image Recognition
::: Slashdot

Are We Entering a “Golden Age of Quantum Computing Research”?
::: Slashdot

Why Facebook’s News Experiment Matters to Readers
::: The New York Times

10359221_803259386379056_3486306972749692534_n

Mobile carriers in Europe will reportedly block ads in effort to bully Google
::: The Verge

Announcing Rust 1.0
::: The Rust Programming Language

#lisp LispWorks 7 with its GTK+ native UI running on ARM / Odroid, example screenshot
::: RainerJoswig

Want to appreciate Linux/Mac Terminal?
::: svpino

twobeer

The Solution To Argentina’s Banking Problems Is To Go Cashless
::: Slashdot

Un semplice esperimento di intelligenza artificiale
::: the secrets of ubuntu

Linino-Enabled Arduino Yun Shrinks In Size and Cost
::: Slashdot

buonascuola

Lisp – loop per cinture nere – 3

2BContinuo con Peter.

Accumulatore di valore

Le clausole di accumulo del valore sono forse la cosa più potente di loop. Le clausole di iterazione forniscono una sintassi concisa per esprimere cicli ma non sono poi molto diverse dal meccanismo fornito da do, dolist e dotimes.

Le clausole per l’accumulatore di valore forniscono invece una notazione concisa per una manciata di operazioni che hanno a che fare con l’accumulo durante il ciclo. Ogni clausola inizia con un verbo e segue questo modello:

verb form [ into var ]

Ogni giro del ciclo una clausola d’accumulo valuta form e salva il valore nel modo determinato da verb. Con una subclausola into il valore è salvato dentro la variabile var. La variabile è locale al ciclo se è stata dichiarata con with. Senza la subclausola into l’accumulo avviene per il valore dell’intera espressione del ciclo.

I valori possibili per il verbo sono collect, append, nconc, count, sum, maximize e minimize. Sono presenti sinonimi: collecting, appending, nconcing, counting, summing, maximizing e minimizing.

Una clausola collect costruisce una lista contenente tutti i valori di form nell’ordine in cui sono visti. Risulta particolarmente utile e efficiente e salva dal dover farlo a mano (Peter riporta nella nota 5 un esempio panicoso per una cosa semplice). Collegato a collect ci sono append e nconc. Anche questi accumulano i valori in una lista ma uniscono i valori, che devono essere liste, in una singola lista come le funzioni append e nconc. Ricordarsi che nconc è la versione distruttiva di append e quindi –vedi tu :wink:

Le rimanenti clausole sono usate per accumulare valori numerici. count conta il numero di volte che form è vera, sum colleziona il totale corrente dei valori di form, maximize colleziona i valori più grandi visti finora e minimize i più piccoli. Esempio, definiamo *random* che contiene una lista di numeri casuali:

l14

Il loop seguente ritorna una lista contenente varie informazioni riassuntive per quei numeri:

l15

Nota personale: al volo mi son detto che non funziona, leggere tutto il codice, compreso l’ordine con cui viene costruita lista ritornata :wink:

Esecuzione condizionale

Siccome una clausola può contenere forms Lisp arbitrarie si possono usare tutte le espressioni che si vuole, inclusi costrutti if e when; così il seguente è il modo di scrivere un ciclo che scrive solo i numeri pari compresi tra uno e dieci:

l16

Tuttavia a volte si vuole il controllo condizionale a livello delle clausole. Per esempio supponiamo di voler solo la somma dei numeri pari da uno a dieci. Non si può scrivere un ciclo con un do perché non c’è modo di chiamare sum i nel mezzo di una form Lisp regolare. In questo caso serve una delle espressioni condizionali proprie di loop, così:

l17

loop fornisce tre costrutti condizionali tutti con lo schema:

conditional test-form loop-clause

dove conditional può essere if, when e unless. La test-form, se presente è una form Lisp regolare e loop-clause può essere una clausola di accumulazione (count, collect, ...) una clausola di esecuzione incondizionale o un’altra clausola di esecuzione. Clausole di loop multiple possono  essere aggiunte a una singola clausola condizionale unendole con and.

Come zucchero sintattico nella prima clausola dopo test-form si può usare la variabile it per riferirsi al valore ritornato da test-form. Per esempio il seguente ciclo colleziona i valori non-nil trovati in some-hash quando cerca le chiavi in some-list:

(loop for key in some-list when (gethash key some-hash) collect it)

Nota personale: segue un frase che non mi torna, dubbio, typo? Ma mi sembra che si possa omettere.
Una clausola if o when esegue loop-clause se test-form viene valutata vera, unless invece se questa vale nil. In loop if e when sono solo sinonimi.

Tutte tre le clausole condizionali possono avere un’alternativa else che è seguita da una o più altre clausole di loop unite con and. Quando le clausole condizionali sono annidate il set delle clausole di una clausola condizionale interna può essere chiuso con la parola end. end è opzionale quando non richiesto per disambiguare un condizionale annidato, l’end può essere inferito dalla fine del loop o dall’inizio di un altra clausola non unita da and.

Esempio (sciocco) che visualizza vari condizionali. La funzione update-analysis viene chiamata ogni volta attraverso il ciclo con gli ultimi valori delle varie variabili accumulate dalle clausole con i condizionali:

(loop for i from 1 to 100
      if (evenp i)
        minimize i into min-even and 
        maximize i into max-even and
        unless (zerop (mod i 4))
          sum i into even-not-fours-total
        end
        and sum i into even-total
      else
        minimize i into min-odd and
        maximize i into max-odd and
        when (zerop (mod i 5)) 
          sum i into fives-total
        end
        and sum i into odd-total
      do (update-analysis min-even
                          max-even
                          min-odd
                          max-odd
                          even-total
                          odd-total
                          fives-total
                          even-not-fours-total))

dove non avendo update-analysis (OK, si potrebbe fare finta, ci vuole un attimo) devi studiare il codice senza farlo girare. Ma mi sembra non impossibile. Molto poco lispico, sembra Fortran.

Continua :mrgreen:

Lisp – loop per cinture nere – 2

j10Seguendo Peter continuo da qui.

Cicli con collezioni e packages

Le clausole for per iterare le liste sono molto più semplici di quelle aritmetiche. Supportano solo due frasi proposizionali: in e on.

Una frase nella forma:

for var in list-form

cicla var per tutti gli elementi della lista prodotta dalla valutazione di list-form:

l2

A volte ci può essere anche la clausola by per percorrere la lista al contrario. Il default è cdr ma si può usare qualunque funzione che torni una lista. Per esempio per prenderne uno sì e uno no:

l3

L’on è usato per ciclare var sulle cons cells che formano una lista:

l4

E questa frase può avere anche un by:

l5

Ciclare su un vettore (comprese stringhe e bit vectors) è come per le liste solo che si usa across invece di in:

l6

Iterare un hash table o un package è leggermente più complicato perché questi hanno differenti set di valori che possiamo voler saltare –chiavi o valori nella table e simboli nel package. Entrambi i tipi di queste iterazioni seguono lo stesso schema, la cui forma base è:

(loop for var being the things in hash-or-package ...)

Dove per le tables i possibili valori per things sono hash-keys e hash-values che causano var a assumere i successivi valori delle keys o dei valori della hash table. La form hash-or-package è valutata una sola volta per produrre un valore che dev’essere una hash table.

Per iterare in un package things può essere symbols, present-symbols e external-symbols che causano var a collegarsi a ogni simbolo accessibile nel package (cioè internato o importato nel package) o in ogni simbolo che è stato esportato dal package. La form hash-or-package è valutata per produrre il nome del package che è visto come nella find-package o un oggetto package. Sono disponibili anche sinonimi per parti della clausola. al posto di the si può usare each; si può usare of invece di in; e things può essere al singolare.

Infine, siccome si vogliono spesso sia le keys che i valori della hash table queste clausole supportano un uso di subclausole alla fine della clausola per la hash:

(loop for k being the hash-keys in h using (hash-value v) ...)
(loop for v being the hash-values in h using (hash-key k) ...)

Entrambe questi cicli collegano k a ogni key nella hash e v al corrispondente valore. Notare che il primo elemento della subclausola using dev’essere nella singular form (Don’t ask me why loop’s authors chickened out on the no-parentheses style for the using subclause. (cit.)).

Iterazioni equals-then

Se nessuna delle altre clausole per for funziona per quel che devi fare allora devi prendere il controllo completo con la clausola equals-then. Questa è simile a quella del do ma in modo più algolico. Il modello è:

(loop for var = initial-value-form [ then step-form ] ...)

dove var è il nome della variabile del ciclo. Il suo valore iniziale è ottenuto valutando initial-value-form una sola volta prima della prima iterazione. In ogni iterazione susseguente step-from è valutato e il suo valore diventa il valore di var. Senza la parte then della clausola initial-value-form è rivalutato per ogni iterazione per fornire un nuovo valore. Notare che questo è diverso da una clausola do senza step.

step-form può riferirsi a altre variabili di cicli, incluse variabili create da altre clausole susseguenti nel ciclo. Per esempio:

l7

(matto :evil: imho).
Notare che ogni clausola è valutata nell’ordine in cui compare. Quindi nel ciclo precedente nella seconda iterazione x è settato al valore di y prima che y cambi (cioè 1) ma y è poi settato al al suo vecchio valore (ancora 1) e al nuovo valore di y (qui ho cambiato, forse typo).
Se l’ordine delle clausole è invertito il risultato cambia:

l8

Spesso si vuole il passo per forms per variabili multiple valutate prima di ognuna che le nuove variabili assuma il suo nuovo valore, come il do gestisce il passo per le sue variabili. In questo caso si possono unire clausole for multiple sostituendole tutte tranne la prima con and. Esempio:

l9

Nota personale: io la frase precedente l’avrei semplificata di molto :evil:

Variabili locali

Mentre le variabili principali richieste dentro a un loop sono usualmente dichiarate implicitamente nella clausola for a volte ne servono di ausiliarie che si dichiarano con with:

with var [ = value-form ]

Il nome var diventa il nome di una variabile locale che cessa di esistere quando il loop finisce. Se il with contiene una parte = value-form la variabile viene inizializzata prima della prima iterazione a quel valore.

with multipli possono apparire in un loop: ogni clausola è valutata indipendentemente nell’ordine in cui appare e il valore assegnato prima di procedere con la clausola successiva, permettendo a variabili seguenti di dipendere da valori per variabili già dichiarate. Variabili mutualmente indipendenti possono essere dichiarate con un with con clausole and tra le dichiarazioni.

Destrutturazione di variabili

loop può destrutturare liste di valori assegnati alle variabili del ciclo. Questo consente di usare il valore di liste che altrimenti verrebbe assegnato a una variabile del ciclo, allo stesso modo di destructuring-bind ma meno elaborato. In sostanza si può rimpiazzare ogni variabile del ciclo in una clausola for o with con un albero di simboli e il valore della lista che dev’essere assegnata a una semplice variabile può invece essere destrutturata in variabili nominate dai simboli dell’albero (capito niente, nada, zilch!). Esempio semplice:

l10

L’albero può contenere anche liste puntate nel qual caso il nome dopo il punto agisce come parametro &rest, venendo collegato a ogni elemento rimanente della lista. Questo torna particolarmente utile con cicli for/on siccome il valore è sempre una lista. Esempio, questo ciclo per scrivere una lista delimitata da virgole:

l11

può essere riscritto così:

l12

Se si vuole ignorare un valore nella lista destrutturata si può usare nil al posto del nome della variabile:

l13

Se la lista destrutturata contiene più variabili dei valori presenti le variabili extra sono settate a nil, rendendo tutte le variabili come se fossero parametri &optional. Cosa diversa dai parametri &key.

Continua :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à :wink: :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 :grin:
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 :evil:

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 :oops: :cry: :evil:
Ecco un paio di link:

Poi forse continuo, tentando di rimediare :mrgreen:

Lisp – loop per cinture nere – 1

programmer_joke8Il titolo è quello di Peter, io avrei preferito un rifermento ai ninja ma mi adeguo :wink:
Abbiamo già incontrato loop in passato e abbiamo visto che è un linguaggio a sé per scrivere costrutti iterativi.

Uh! inventare un linguaggio solo per i cicli? Beh, se ci si pensa un po’ ha senso…

La macro loop ha diverse parti, una delle critiche principali che le vengono mosse è che è troppo complessa. Le vedremo sistematicamente in un tour e poi vedremo come assemblarle.

Le parti di un loop

Con loop si possono fare le seguenti cose:

  • trattare passo-passo variabili e strutture di dati (arrays p.es.);
  • raccogliere, contare, sommare, trovare valori minimo e massimo;
  • eseguire espressioni Lisp arbitrarie;
  • decidere quando terminare il loop;
  • fare tutte queste condizionalmente.

Inoltre loop fornisce la sintassi per:

  • creare variabili locali da usarsi nel loop;
  • specificare espressioni Lisp da eseguirsi prima e dopo il loop vero e proprio.

La struttura base di un loop è un set di clausole, ognuna delle quali inizia con una loop keyword (che non sono propriamente keywords ma si chiamano così). Come ognuna di esse sia trattata dipende dalla keyword stessa. Anticamente abbiano già visto for, collecting, summing, counting, do e finally.

Iterazioni

La maggior parte dei cosidetti controlli d’iterazione (iteration control) iniziano con la keyword for o un suo sinonimo come as (si tenta di imitare l’inglese per cui ci sono i sinonimi) seguiti dal nome di una variabile. Quel che segue la variabile dipende dal tipo della clausola.

Le clausole per un loop possiamo dividerle come segue:

  • intervalli di numeri, crescenti o decrescenti, per intervalli specificati;
  • elementi individuali di una lista;
  • le cons cells che formano una lista;
  • gli elementi di un vettore, inclusi subtipi come stringhe e bit vectors;
  • le coppie di una hash table;
  • i simboli in un package;
  • i risultati di valutazioni ripetute di una data form.

Un singolo loop può avere clausole for multiple ciascuna con la propria variabile per la clausola. Quando un loop for ha clausole multiple il loop termina appena una delle clausole for raggiunge la condizione di fine. Per esempio il loop seguente:

(loop
  for item in list
  for i from 1 to 10
  do (something))

cicla per un massimo di dieci iterazioni ma si può fermare prima se la lista contiene meno di dieci elementi.
Nota: da fortrainer mi verrebbe di scrivere diversamente; devo convertirmi.

Cicli contanti

Clausole di iterazioni aritmetiche controllano il numero di volte per cui il ciclo verrà eseguito, eseguendone il corpo una volta per passo. Queste clausole consistono da una a tre delle seguenti frasi proposizionali dopo for (o as): la from where phrase, la to where phrase e la by how much phrase (se traduco si capisce meno, imho).

La from where phrase specifica il valore iniziale per la variabile della clausola. Consiste in una delle preposizioni from, downfrom, o upfrom seguita da una form che fornisce il valore iniziale (un numero).

La to where phrase specifica il punto di stop per il ciclo, consiste di una delle preposizioni to, upto, below, downto o above seguita da una form che fornisce il valore di stop. Con upto e downto il ciclo viene terminato (senza eseguire ancora il corpo) quando la variabile raggiunge il punto di stop; con below e above si ferma un’iterazione prima  (come in Python). Il by how much phrase consiste della proposizione by e una form che deve valutare a un numero positivo. la variabile viene variata (su o giù come stabilito dalle altre frasi) per questo valore per ogni iterazione o per uno se omessa.

Si deve specificare almeno una di queste frasi proposizionali. Il default è di partire da zero, incrementare la variabile di uno per ogni iterazione e proseguire per sempre o, più probabilmente, fino a quando qualche altra clausola termina il ciclo. Si possono modificare questi defaults aggiungendo le frasi proposizionali opportune. Il solo inghippo è che se si usa un passo decrementante non c’è default per from where value e se ne deve specificare uno con from o downfrom. Così il seguente:

l0

funziona ma questo no:

(loop for i downto -10 collect i)         ; wrong

perché è indefinito e si deve scrivere:

l1

Inoltre siccome loop è una macro eseguita a compile time non è capace di determinare la direzione della variabile del passo basata solo sulle preposizioni (non sui valori delle forms che possono non essere note fino a runtime). Così la seguente:

(loop for i from 10 to 20 ...) ; OK

funziona siccome il default è il passo incrementale, ma questa:

(loop for i from 20 to 10 ...) ; NO, wrong

non sa come contare da 20 a 10. Peggio ancora non da errore perché i è sempre maggiore di 10; si deve scrivere così:

(loop for i from 20 downto 10 ...) ; OK

oppure:

(loop for i downfrom 20 to 10 ...) ; OK

Infine se si vuole semplicemente un ciclo che si ripeta un certo numero di volte si può sostituire:

for i from 1 to number-form

con la clausola repeat:

repeat number-form

Queste clausole sono identiche tranne che repeat non crea una variabile del loop.

Al solito, una reference torna utile, io uso Bert.

Continua, prossimamente :mrgreen:

Lisp – packages e simboli – 3

l6Oggi finisco il capitolo, continuando da qui.

Mettere nei packages librerie riusabili

OK, difficoltà di traduzione, l’originale è “Packaging Reusable Libraries”: Sergio! :wink:
Lavorando con il database delle mail, iniziato nel post precedente, si possono scrivere diverse funzioni per memorizzare e ricaricare testo che non riguarda per niente le mail. E queste funzioni possono risultare utili per altre applicazioni e quindi conviene spostarle in un package ad hoc come libreria (si può dire ripackaggiarle?). Occorre definire un nuovo package ma questa volta esporteremo certi nomi per renderli disponibili a altri packages.

p19

Usiamo il package COMMON-LISP perché abbiamo bisogno delle funzioni standard. La clausola :export specifica i nomi che saranno esterni e quindi accessibili per i packages che usaranno COM.GIGAMONKEYS.TEXT-DB con :use. Dopo aver definito questo package si può cambiare la definizione del package principale dell’applicazione con:

p20

Adesso il codice scritto in COM.GIGAMONKEYS.EMAIL-DB può usare nomi qualificati per riferirsi a simboli sia in COMMON-LISP che in COM.GIGAMONKEYS.TEXT-DB. Tutti gli altri nomi si riferiscono al package COM.GIGAMONKEYS.EMAIL-DB.

Importare nomi individuali

Supponiamo adesso di trovare una libreria di funzioni per manipolare  messaggi. I nomi nella libreria sono esportati dal package COM.ACME.EMAIL così possiamo usare :use per accedere agevolmente a questi nomi. Ma supponiamo che si voglia usare solo una funzione da questa libreria  e che altri simboli siano esportati con nomi che vanno in conflitto con quelli che stiamo usando. In questo caso si può importare il simbolo singolo con la clausola :import-from nella form defpackage. Per esempio se vogliamo usare parse-email-address si può scrivere:

Nota: qui per usare l’esempio ho dovuto definire il package COM.ACME.EMAIL e la funzione (finta) parse-email-address, così:

p21

adesso posso riprendere:

p22

Adesso ovunque il nome parse-email-address nel codice nel package COM.GIGAMONKEYS.EMAIL-DB viene letta come un simbolo da COM.ACME.EMAIL. Se si vuole importare più simboli si possono includere più nomi in una singola :import-from. Un defpackage può anche avere più clausole :import-from per importare da diversi packages.

Può anche capitare di venirsi a trovare nella situazione opposta di un package che esporta diversi nomi ma ne voglio solo qualcuno. In questo caso invece di elencarli in :import-from si può dire :use per ereditarli tutti e poi usare :shadow per quelli che non voglio. Salto l’esempio dettagliato di Peter perché dovrei creare tutto il package finto COM.ACME.TEXT.

Una situazione simile capita quando si importano due packages che esportano lo stesso nome. In questo caso il reader non sa quale ereditare e bisogna risolvere l’ambiguità nascondendone (shadow) uno. Ma se i nomi da nascondere sono diversi si può ricorrere alla clausola :shadowing-import-from. Per esempio si può scrivere qualcosa come:

(defpackage :com.gigamonkeys.email-db
  (:use
   :common-lisp
   :com.gigamonkeys.text-db
   :com.acme.text)
  (:import-from :com.acme.email :parse-email-address)
  (:shadow :build-index)
  (:shadowing-import-from :com.gigamonkeys.text-db :save))

Meccanica del packaging

Help Sergio! :wink:
Finora abbiamo visto le basi per le situazioni più comuni. Ma c’è altro, come organizzarsi per usare diversi packages. Ecco alcune regole base, dove mettere le forms defpackage relative al codice che usa i packages attraverso in-package.

Siccome i packages sono usati dal reader un package dev’essere definito prima di poter usare load o compile-file per un file che contiene un espressione in-package che commuta (switch) a questo package. I packages devono altresì essere definiti prima che altre forms defpackage si riferiscano a loro. Per esempio per peter scrivere :use COM.GIGAMONKEYS.TEXT-DB in COM.GIGAMONKEYS.EMAIL-DB, allora il defpackage di COM.GIGAMONKEYS.TEXT-DB dev’essere valutato prima del defpackage di COM.GIGAMONKEYS.EMAIL-DB.

Il miglior inizio per essere sicuri che i packages esistano quando servano è di mettere tutti i defpackages in un file separato dal codice che necessiterà di questi packages. Alcuni creano un file foo-package.lisp per ogni package e altri un singolo packages.lisp che contiene tutte le forms defpackage. valide entrambe ma con la prima si dovranno usare loads individuali nel giusto ordine in funzione con le dipendenze relative.

In ogni caso una volta che le forms defpackage sono state separate dal codice che leggerà i packages che definiscono si deve usare load per caricarli. Per programmi semplici basta usare load per il file che contiene le forms, eventualmente avendolo precompilato con compile-file. Qui Peter la fa lunga ma mi sembra ripetitivo (o non ho capito, serve sempre l’esempio).

Fare questo (che non ho capito) manualmente diventa tedioso dopo un po’.
Nota: io che sono vecchio e vengo dal Fortran (e anche ripetitivo) queste cose mi ricordano make che usavano i C-isti ma non i fortrainers :wink:

Per programmi semplici si può automatizzare scrivendo un file load.lisp che contiene le chiamate a load e compile-file nell’ordine appropriato e quindi semplicemente usare load per questo file. Per programmi più complessi si può usare una system definition facility, per esempio Peter usa ASDF (Another System Definition Facility), forse ci dirà cos’è, altrimenti c’è pronta la googlata a Stack Overflow :grin:

L’altra regola pratica è che ogni file deve contenere esattamente una form in-package e dev’essere la prima form nel file (non contando i commenti). I files contenenti forms defpackage devono iniziare con (in-package "COMMON-LISP-USER") e tutti gli altri files devono contenere un in-package di uno dei nostri packages.

Se si viola questa regola e si passa da uno all’altro si confonde il lettore umano che non s’accorge del secondo in-package. Con qualche implementazione si confonde anche l’ambiente.

Per contro è normale avere più files che leggono lo stesso package, ognuno con un identica form in-package, dipende da come ti organizzi.

Una roba sui nomi dei packages. Questi vivono in un namespace piatto, i nomi sono solo stringhe e packages diversi devono avere nomi diversi. Quindi se non si lavora isolati occorre seguire le convenzioni che minimizzino le possibilità di conflitti. Parecchi lispers adottano la convenzione di Java, come quelle usate in questo post, consistenti nell’inverso dei nomi dei domini Internet seguiti da un punto e una stringa significativa.

Trabocchetti dei packages

Sergio qui c’è gotcha :wink:
Quando si diventa esperti si fa senza stare a pensarci su ma un paio di cose che i niubbi incontrano sono panicanti.

Il primo capita con la REPL. Se si sta tentando di usare una libreria che usa una funzione come:

(foo)

si cade nel debugger con un messaggio come:

attempt to call `FOO' which is an undefined function.
   [Condition of type UNDEFINED-FUNCTION]

Restarts:
  0: [TRY-AGAIN] Try calling FOO again.
  1: [RETURN-VALUE] Return a value instead of calling FOO.
  2: [USE-VALUE] Try calling a function other than FOO.
  3: [STORE-VALUE] Setf the symbol-function of FOO and call it again.
  4: [ABORT] Abort handling SLIME request.
  5: [ABORT] Abort entirely from this (lisp) process.

Ah! dimenticato di caricare la libreria. Quindi:

(use-package :foolib)

ma salta fuori nuovamente il debugger:

Using package `FOOLIB' results in name conflicts for these symbols: FOO
   [Condition of type PACKAGE-ERROR]

Restarts:
  0: [CONTINUE] Unintern the conflicting symbols from the `COMMON-LISP-USER' package.
  1: [ABORT] Abort handling SLIME request.
  2: [ABORT] Abort entirely from this (lisp) process.

Uh! La prima volta che si è chiamata foo il reader l’ha internata in CL-USER e adesso il nuovo nome va in conflitto con quello esistente.

Non tutto è perduto perché la prima alternativa fa quello che ci vuole: disinterna la vecchia foo e carica quella nuova, come previsto.

Questo tipo di problema capita anche quando si caricano e compilano files. La soluzione è la stessa.

L’altro problema è essenzialmente l’inverso di questo ppena visto. Nel caso si sia definito un package (p.es. MY-APP) che ne usa un altro (FOOLIB).  Quest’ultimo esporta la funzione foo con altri simboli ancora. Se uno di questi, p.es. bar, usa la stessa funzione del mio codice il Lisp non avvisa ma userà la funzione in FOOLIB.

Il trabocchetto è insidioso perché non c’è errore. Tuttavia in alcune implementazioni il valutatore avvisa “redefining BAR, originally defined in?”. SBCL permette il locking di funzioni, chissà cos’è.

L’ultimo trabocchetto è più semplice ma colpisce i niubbi. Si definisce un package che usa COMMON-LISP e forse alcune librerie. Nella REPL cambio su questo package e poi decido di chiudere il Lisp con (quit). Tuttavia quit non è nel COMMON-LISP, è definito dall’implementazione da qualche parte. La soluzione più semplice è di switchare a CL-USER prima di quit-are. O usare –come me– Ctrl-D.

Adesso, dice Peter, sappiamo quasi tutto del Common Lisp. Quando fa così chissà cosa sta preparando :mrgreen:

eval – da evitare se possibile

l1Recentemente sono capitato qui: Why exactly is eval evil? cercando altro (eval-when). A volte la serendipità di Google è astoundicante sorprendente.

Perché io a eval ci sono affezionato, non solo con il Lisp. L’ho usata diverse volte, anche nel web. E proprio lì manca qualsiasi controllo, difesa da tentativi di hack cattivi.

Ma la ragione principale per i principianti (me too) è: non ne hai bisogno.

Esempio, usando Common Lisp:

(let ((ops '(+ *)))
  (dolist (op ops)
    (print (eval (list op 2 3 4)))))

si può scrivere meglio come:

(let ((ops '(+ *)))
  (dolist (op ops)
    (print (funcall op 2 3 4))))

e0

poiché oltre alle espressioni sono valutate anche le funzioni. Stesso problema con le macros.

Quando un principiante pensa di aver bisogno di eval deve controllare se invece non usare funcall, reduce o apply.

e1

Poi c’è chi è più espressivo: “eval (in any language) is not evil in the same way that a chainsaw is not evil. It is a tool.” E c’è un lungo elenco di attrezzi che possono essere ugualmente dannosi: gotos, lock-based threads, continuations, macros, pointers, …

E se ti capita di voler usare uno di questi ti devi chiedere una catena di tre “perché?”:

  • perché devo usare eval? per via di foo;
  • perché foo è necessario? perché …;
  • se arrivi alla fine della catena e continui a pensare che sia la cosa giusta fallo, testalo, controlla se è sicuro; ma fallo.

OK, la pagina continua, con esempi da vedere.
Personalmente mi convinco sempre di più che

  • sono niubbo — assay;
  • Stack Overflow rockz!

La Wiki (come farei senza, anche lei rockz) esamina anche altri linguaggi, qui.

conf-t

Mentre io vado dietro a queste cose da vecchi (ne ho un paio quasi pronte) i miei giovani tweeps … sapeste (forse a breve sapremo) :wink:

Lisp – packages e simboli – 2

j6Continuo da qui a seguire qui.

Tre packages standard

Prima di vedere come definire i nostri, e usarne altri e esportare, shadow e importare simboli vediamo quelli che stiamo già usando.p4

Quando si parte il package corrente è tipicamente COMMON-LISP-USER conosciuto anche come CL-USER. Ogni package ha un nome ufficiale e zero o più nicknames (soprannomi). CL-USER usa COMMON-LISP che è quello che esporta tutti i nomi definiti dallo standard Common Lisp, quelli disponibili subito.

Se vogliamo il nome qualificato:

p5

E si può usare anche il nick CL:

p6

Siccome *x* non è un simbolo di COMMON-LISP si può scrivere:

p7

il reader legge defvar come il simbolo dal package COMMON-LISP e *X* come un simbolo in COMMON-LISP-USER.

La REPL non può partire nel package COMMON-LISP perché non sono autorizzato a inserirci simboli. COMMON-LISP-USER serve come package di appunti (scratch) dove posso creare i miei nomi avendo contemporaneamente un pronto accesso a COMMON-LISP. Si può avere accesso anche a altri simboli esportati da altri packages, per vedere quali simboli COMMON-LISP-USER eredita si può fare così:

p8

E per vedere da che package viene un simbolo:

p9

Simboli ereditati possono venire anche da altri.

Tipicamente tutti i packages che si definiscono useranno anche COMMON-LISP, cosi non è necessario scrivere così:

(cl:defun (x) (cl:+ x 2))

Il terzo package standard è il package KEYWORD, quello che il reader usa per aggiungere i nomi che iniziano con due-punti. Quindi è possibile riferirsi a qualsiasi keyword symbol con un package qualificato esplicito della keyword, così:

p10

Definire i propri packages

Finché si usa la REPL COMMON-LISP-USER è sufficiente ma quando si comincia a codificare seriamente diventa necessario definire nuovi packages in modo che differenti programmi caricati nello stesso ambiente Lisp non vadano in conflitto per i nomi.

Ma prima di vedere come definire packages dobbiamo capire cosa i packages non fanno. I packages non forniscono controllo diretto su chi può chiamare una funzione o accedere a che variabile. Forniscono un controllo di base sui namespaces ma non è finché l’evaluator che il simbolo è interpretato come nome di fuzione o variabile o altro ancora. Quindi non ha senso parlare di esportare una funzione o una variabile da un package. Si possono esportare simboli per rendere più facile riferirsi a certi nomi ma il sistema non consente di restringere l’uso di questi nomi (a differenza di altri linguaggi).

Si possono definire packages con la macro defpackage, che consente non solo di crearne uno nuovo ma anche di specificare quali usa, che simboli esporta, che simboli importa da altri packages e come risolvere i conflitti di nomi creando shadowing symbols.

Per vedere tutto questo Peter ci scrive un programma che organizza le mail in un database. Il programma è puramente ipotetico, serve a far vedere come i packages usati possono essere strutturati.

Il primo package che serve è uno che fornisce un namespace per l’applicazione.. vogliamo poter nominare le nostre funzioni, variabili e quant’altro senza preoccuparci di nomi non correlati. Definiamo quindi il package con defpackage:

p11

Questo definisce il package COM.GIGAMONKEYS.EMAIL-DB che eredita tutti i simboli di COMMON-LISP. In qualche implementazione la form (:use :common-lisp) è implicita, ma non si sa mai; può anche essere scritta come (:use :cl).

Si hanno diverse possibilità su come rappresentare i nomi dei packages e i simboli dentro defpackage. I packages e i simboli sono nominati con stringhe ma nella fform di defpackage si possono specificare con string designators. Uno string designator può essere una stringa che designa se stessa, un simbolo che designa il suo nome o un carattere che designa stringa di un singolo carattere. Usando keyword symbols, come nell’esempio precedente, è lo stile normale che consente di scrivere in minuscolo e il reader converte in maiuscolo. Si può anche scrivere defpackage con stringhe ma si deve scrivere tutto in maiuscolo perché i nomi sono di solito tutti maiuscoli per via della convenzione seguita dal reader. L’uso di keyword ha anche il vantaggio di funzionare con Allegro che usa il modern mode, senza conversione in maiuscolo.
Quindi:

p12

Si possono usare anche simboli non keyword –i nomi non sono valutati– ma quando sono letti sono internati e non ha senso.

Per leggere codice in questo package lo si deve rendere corrente con la macro in-package:

p13

che, come si vede, cambia il valore di *package*, modificando come la REPL legge le espressioni seguenti, fino alla nuova chiamata a in-package. Similmente se si include una in-package in un file caricato con load o compilato con compile-file questo cambierà il package influenzando come le espressioni sono lette. Ci sono vantaggi a usare in-package invece di setf-are semplicemente la variabile globale.

Con il package correntemente settato a COM.GIGAMONKEYS.EMAIL-DB oltre ai nomi ereditati da COMMON-LISP si possono usare nomi per quel che vogliamo. Quindi posso definire la funzione hello-world che può coesistere con la funzione precedentemente definita in COMMON-LISP-USER.

p14

Adesso rendo corrente il nuovo package e posso definire una nuova hello-world in questo package:

p16

testarla:

p17

e ritornare a CL-USER dove ho la vecchia funzione:

p18

Continua :mrgreen:

Lisp – packages e simboli – 1

click

click

Peter Seibel è più enfatico: “Programming in the Large: Packages and Symbols” ma poi mi auto-impanichisco, sapete com’è :wink:

Abbiamo già visto anticamente come il Lisp reader traduce i nomi testuali in oggetti per passarli al valutatore, rappresentandoli come un tipo di oggetti chiamati simboli. Salta fuori che questa cosa di avere un tipo di dati specificatamente per rappresentare i nomi torna utile per diverse occasioni. È la programmazione simbolica, invece dell’usuale programmazione numerica. Qui non ci occuperemo di questo ma di più immediati e pratici aspetti di gestione dei nomi: come evitare conflitti dei nomi in parti di codice sviluppate indipendentemente.

Supponiamo di scrivere un programma e di voler usare una libreria fatta da chissachì (OK, third-party library). Non voglio avere la necessità di sapere i nomi di ogni funzione, macro, variabile o classe usata internamente nella libreria. I nomi che uso nel programma devono essere distinti da quelli della libreria. Allo stesso tempo per certi tipi di nomi, quelli delle API pubbliche, li voglio accessibili prontamente nel mio programma.

In Common Lisp questo problema di namespace (non so la traduzione in italiano, non so se esiste e comunque io ho sempre detto così) si riduce a una questione di controllo di come il reader traduce i nomi testuali in simboli. Se si vuole che due occorrenze dello stesso nome siano considerate le stese dal valutatore è necessario di assicurarsi che il reader usi lo stesso simbolo per i due nomi. Per contro se si vuole che i nomi siano considerati distinti, anche se testualmente uguali, è necessario che il reader crei simboli diversi p rappresentarli.

Come il reader usa i packages

Cominciamo con la sintassi dei nomi intesi dal reader e come questa si correla ai packages. Per il momento possiamo pensare il package come una tabella che mappa stringhe a simboli. Vedremo che la realtà è piu flessibile ma per adesso ci basta questo. Ogni package ha un nome che può essere usato dalla funzione find-package.

Le due funzioni che il reader usa per accedere a una mappatura nome-simbolo in un package sono find-symbol e intern. Entrambe prendono una stringa e, opzionalmente un package che se non fornito viene assunto come il valore della variabile *package*, detto current package.

find-symbol cerca nel package per un simbolo con il nome corrispondente alla stringa passata e lo ritorna, o nil se non lo trova. Similmente intern ritorna un simbolo se esiste ma se non c’è ne crea uno nuovo con quel nome e lo aggiunge al package.

La maggior parte dei nomi sono non qualificati (unqualified) cioè nomi senza due-punti. Quando il reader legge un nome come non qualificato lo traduce in un simbolo convertendo ogni lettera non escapata in maiuscolo e passando il risultato a intern. Quindi ogni volta che il reader legge lo stesso nome nello stesso package prende lo stesso oggetto. Questo è importante perché il valutatore usa questa identità dell’oggetto dei simboli per determinare che funzione, variabile o altro elemento un dato simbolo si riferisce. Quindi la ragione di un espressione come (hello-world) risulta nel chiamare una particolare funzione hello-world perché il reader ritorna lo stesso simbolo quando legge la chiamata alla funzione come quando ha letto la form defun che ha definito la funzione.

Un nome contenete uno o due due-punti è un nome package-qualificato. Quando il reader legge questo nome lo divide ai due-punti e usa la prima parte come il nome del package e la seconda come nome del simbolo.

Un nome contenente un singolo due-punti deve riferirsi a un external symbol, uno che il package esporta per uso pubblico. Se il package non contiene un simbolo con quel nome o questo non è stato esportato il reader segnala un errore. Un nome qualificato con un doppio due-punti può riferirsi a qualunque simbolo nel package nominato ma è una cattiva idea –i nomi il cui uso è previsto sono quelli esportati, non i privati.

Altre due cose che il reader conosce sono quelle per le keyword symbols e i simboli uninterned. Le keyword symbols sono scritte con un due-punti iniziale, sono chiamate keyword e esportate automaticamente. Inoltre quando il reader interna un simbolo nella keyword definisce una variabile costante con quel simbolo sia come nome che valore. Ecco perché si possono usare le keywords in liste di argomenti senza quotarle, quando compaiono nella posizione di valore si valutano per loro stesse, quindi:

p0

I nomi delle keyword symbols, come tutti i simboli, sono convertiti in maiuscolo dal reader prima di essere internati. Il nome non include il due-punti iniziale:

p1

I simboli non internati sono scritti con il prefisso #:. Questi nomi (escluso #:) sono convertiti in maiuscolo e tradotti in simboli, ma non sono internati in nessun package; ogni volta che il reader legge un nome #: crea un nuovo simbolo, quindi:

p2

Capita mai di dover trattare questo ma a volte si vedono quando si visualizza una s-expression contenente un simbolo ritornato dalla funzione gensym:

p3

Un po’ di vocabolario per packages e simboli

La mappatura da nomi a simboli in un package è un po’ più flessibile di una semplice tabella di ricerca (lookup table). C’è questa tabella ma un simbolo può essere reso accessibile attraverso un nome non qualificato in un dato package in altri modi. Per capirci serve un po’ di vocabolario.

Tutti i simboli in un dato package che possono essere trovati con find-symbol sono detti accessibili in quel package. In altre parole i simboli accessibili in un package sono quelli cui ci si può riferire con nomi non qualificati quando il package è quello corrente.

Un simbolo può essere accessibile in due modi. Il primo è per il nome-simbolo (name-to-symbol) della tabella del package che contiene una voce per il simbolo, nel qual caso il simbolo è detto presente nel package. Quando il reader interna un nuovo simbolo in un package questo viene aggiunto alla tabella nome-simbolo. Il package in cui un simbolo è internato per la prima volta è chiamato home package del simbolo.

L’altro modo con cui un simbolo può essere accessibile in un package è se il package lo eredita (inherits). Un package eredita simboli da altri packages usando gli altri packages. Solo i simboli external sono ereditati. Un simbolo è reso external in un package esportandolo. Oltre a causare di essere ereditato un simbolo l’esportarlo lo rende accessibile come visto con il nome qualificato con i due-punti.

Per rendere la mappatura da nomi a simboli deterministica il sistema del package consente solo un simbolo di essere accessibile per ogni nome. Cioè un package nn può avere un simbolo presente e uno ereditato con lo stesso nome o ereditare due diversi simboli da packages diversi con lo stesso nome. Tuttavia si possono risolvere questi conflitti rendendo uno dei simboli accessibili uno shadowing symbol, che rende gli altri simboli con lo stesso nome inaccessibili. Oltre al suo nome nella tabella nome-simbolo ogni package contiene una lista di shadowind symbols.

Un simbolo esistente può essere importato in un altro package aggiungendolo alla tabella nome-simbolo del package. Quindi lo stesso simbolo può essere presente in più packages. A volte s’importa un simbolo per renderlo accessibile senza usare il suo home package, altre perché solo i simboli presenti possono essere esportati o essere shadowing symbols. Per esempio se un package deve usare due packages che hanno simboli esterni con lo stesso nome uno dei simboli dev’essere importato nel package in uso per essere aggiunto alla sua shadowing list e rendere inaccessibile ogni altro simbolo.

Infine un simbolo presente può essere disinternato (uninterned) da un package, che causa la sua rimozione dalla tabella nomi-simboli e, se è uno shadowing symbol, dalla shadowing list. Si può voler disinternare un simbolo da un package per risolvere conflitti di nome. Un simbolo che non è presente in nessun package è chiamato simbolo non-internato (uninterned symbol) e non può più essere letto dal reader e viene visualizzato con il prefisso #:.

Pausa :mrgreen:

Visto nel Web – 182

Settimana con tante cose, poi vo racconto (probabilmente, forse) per intanto ecco cosa ho visto nel Web.
CEh2GeqW8AA2tkH
The Big Reverse Of The Web
::: TechCrunch

This guy made a filesystem that doesn’t store files
::: trutherbot

Bill Gates Owes His Career To Steven Spielberg’s Dad; You May, Too
::: Slashdot

BER MetaOCaml — an OCaml dialect for multi-stage programming
::: Lambda the Ultimate

tumblr_nnxqttxV0P1t3op9po1_400

Stigma virtuale
pensateci!
::: L’estinto

Reconsidering Functional Programming
::: Programming in the 21st Century

Visuino – Visual Development for Arduino
::: Visuino

The secret psychology of Facebook
::: The Next Web

WSJ: Facebook to start hosting other sites’ content this May
::: Engadget

CERZ5LtWIAAX7rE
My Top 100 Programming, Computer and Science Books: Part Two
::: Peteris Krumins

bypass redirects in Firefox
::: The Ubuntu Incident

WikiLeaks’ Anonymous Leak Submission System Is Back After Nearly 5 Years
::: Slashdot

Liberals, conservatives unite vs. NSA spying
::: Politico

When someone tells you it’s easy to learn to code
::: ossia

chickenrecorded

GCHQ offered BND equipment to tap Deutsche Telekom in Frankfurt in 2012 in exchange for a copy of the full take
::: e3i5

Mark Shuttleworth: “il primo dispositivo universale entro quest’anno”
::: Dario Cavedon (iced)

Rimuovere virus da Windows utilizzando Ubuntu
::: Chimera Revo

Save The Link
::: Save The Link

Creating Man Pages in Markdown with Ronn
::: Atomic Object

11150814_10206352052221604_173808110107596955_n

Europe Vows To Get Rid of Geo-blocking
::: Slashdot

Nuitka Progress in Spring 2015
::: Nuitka

we need her leadership to save the Internet
::: dcavedon

Apple has $194 billion in cash
::: ValaAfshar

Tenuta in ostaggio dal marito, usa la app di Pizza Hut per chiedere aiuto
::: blackibiza

in forma

Rather than teach everyone to code, let’s teach them to think
::: rob_pike

Go by Example
::: Go by Example

Così i francesi hanno festeggiato i 25 anni del web, mentre i loro politici seppelliscono il diritto alla privacy
::: CheFuturo

Why Was Linux the Kernel That Succeeded?
::: Slashdot

Ubuntu may beat Windows 10 to phone-PC convergence after all
::: PCWorld

140649071-cf25fdd0-953d-492e-872a-699321775ddc

extract an animated gif from a video
::: The Ubuntu Incident

Five programming problems every Software Engineer should be able to solve in less than 1 hour
::: svpino ::: svpino

James Comey: the Man Who Wants To Outlaw Encryption
::: Slashdot

Do-ocracy
questi sono tostassay :grin:
::: suxsonica

Future Holds Large Updates Instead of Stand-Alone Windows Releases
::: Slashdot

power

Il dizionario del cyberbullismo, ultimo esempio della visione schizofrenica di internet
::: Gazzetta di Reggio

Il PC da 9 dollari su Kickstarter è già un successo
sarà vero?
::: tom’s ::: Mashable

A Visual Walk Through Amazon’s Impact On One Seattle Neighborhood
::: Slashdot

Python 3 in Science: the great migration has begun!
::: .py in the sky

The Unison Programming Platform
::: Lambda the Ultimate

tumblr_no36qvqTg91rfd7lko1_400

Iscriviti

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

Unisciti agli altri 85 follower