Qual è l’elemento che rende migliore il nostro computer? L’elevata potenza di calcolo? L’interfaccia intuitiva? La sua connessione ad Internet? O forse il fatto che, qualsiasi sia la nostra necessità, questo sia in grado di eseguire qualsiasi applicazione senza dover essere ogni volta ricostruito fisicamente o ricomprato?

I componenti principali del computer che utilizziamo tutti i giorni consistono in tre blocchi principali: l’hardware (ossia le componenti fisiche del computer), il Sistema Operativo (ciò che permette alle varie parti dell’Hardware di dialogare tra di loro) ed i programmi in esso contenuti ed eseguiti, ciascuno rappresentante un particolare algoritmo, ossia una sequenza finita di istruzioni univocamente interpretabili. Nella nostra pratica comune, quindi, abbiamo un dispositivo unico capace di eseguire qualsiasi programma o algoritmo a nostra discrezione, fintanto che risulti supportato dagli standard del nostro Sistema Operativo.

Un dispositivo capace di eseguire qualsiasi programma opportunamente codificato, senza dover ogni volta essere riconfigurato fisicamente, è per noi un’idea interiorizzata e molto facile da accettare, al punto tale che diamo per scontato il suo funzionamento e non ci preoccupiamo di comprendere i principi matematici che ne costituiscono i fondamenti. Tuttavia, comprendere questi principi è la chiave di volta per vedere chiaramente i limiti e le enormi potenzialità degli strumenti a nostra disposizione, ed essere quindi in grado di apprezzare la meraviglia dei linguaggi che stanno dietro ai programmi che utilizziamo quotidianamente.

L’idea, o progetto, di un dispositivo capace di eseguire non un’unica serie di istruzioni immutabili, ma una serie di istruzioni “mutevoli”, capaci di interpretare altre istruzioni, prende il nome di Macchina Universale, ed è teorizzata e analizzata nel celebre articolo “On Computable Numbers with an Application to the Entscheindungsproblem”, scritto da Alan Turing nel 1936.

Nell’articolo Turing descrive un particolare tipo di calcolatore ideale, munito di un nastro di carta illimitato diviso in caselle, su cui vengono annotati caratteri singoli, e di un dispositivo capace di scorrere il nastro, leggerne i caratteri, scrivere su una casella vuota e cancellare una casella scritta.

Questo calcolatore è capace di cambiare il suo “stato mentale” in base a ciò che legge e di eseguire una serie di istruzioni codificate, disposte all’interno di una matrice di relazioni tra stato mentale attuale e carattere letto sul nastro (es. se il calcolatore legge il carattere “3” ed è nello stato mentale “2” deve spostare il nastro di una casella a sinistra e cancellarne il contenuto).

Questo sistema consente di costruire una macchina calcolatrice per ogni operazione descrivibile tramite un algoritmo, in quanto un algoritmo, essendo per definizione composto da istruzioni finite e prive di ambiguità, può venir riassunto in una matrice di relazioni “stato-carattere” a sua volta finita. La caratteristica limitante di una Macchina di Turing consiste nel fatto che è in grado di eseguire solamente le istruzioni codificate nella sua matrice di relazioni, ossia è in grado di eseguire un unico algoritmo alla volta.

Ma come è possibile ottenere la sopracitata Macchina Universale? Turing ci invita a seguire questo suo ragionamento: immaginiamo di inventare un sistema formale di decodifica degli algoritmi, un sistema che ci permetta di rappresentare ogni formula matematica e aritmetica tramite un’unica sequenza lineare di caratteri. Se costruiamo un linguaggio che permetta di costruire un siffatto isomorfismo, allora sarà possibile costruire una Macchina di Turing capace di codificare e tradurre qualsiasi informazione che rispetti il linguaggio che abbiamo stabilito. A questo punto, che cosa impedisce alla macchina di essere in grado di leggere una stringa di caratteri, decodificarla nella serie di istruzioni che sta a rappresentare e, infine, eseguire la sequenza di istruzioni che ha appena tradotto?

I ragionamenti e le dimostrazioni di Turing illustrano quindi la possibilità di creare un Algoritmo degli Algoritmi capace di ricevere in input un algoritmo codificato e di restituire come output il risultato dell’algoritmo stesso. L’idea di un calcolatore programmabile, per noi ormai più che comune, era pura fantascienza nell’epoca di Turing, quando i calcolatori erano enormi ed intricati complessi meccanici che richiedevano ore e ore di riprogettazione per ogni istruzione diversa (e che ogni tanto s’inceppavano e prendevano fuoco).

Ogni singolo aspetto dell’informatica si basa sulle idee matematiche provenienti da queste formulazioni astratte, a partire dall’architettura più intima dei calcolatori stessi. La Macchina Universale di Turing risulta, a conti fatti, essere composta da:

  • Un nastro di lunghezza idealmente infinita suddiviso in caselle;
  • Un memorizzatore per tener nota dell’attuale stato mentale del calcolatore;
  • Un dispositivo per leggere le caselle;
  • Un dispositivo per cambiare o cancellare il contenuto delle caselle;
  • Un algoritmo codificato all’interno del nastro attraverso simboli;
  • Un algoritmo “universale” di codifica ed esecuzione sottoforma di matrice di relazioni;
  • Dati di input all’interno del nastro e spazio per l’output.

Mentre un computer comune è costituito, a grandi linee, da:

  • Una memoria fissa che contiene al suo interno tutte le informazioni codificate tramite codice binario;
  • Una memoria volatile (ram) capace di memorizzare in forma rapida e temporanea tutte le variabili mutevoli di un programma;
  • Un dispositivo di scrittura, lettura o cancellazione dei dati, governato dalla CPU (central processing unit);
  • Molteplici algoritmi codificati secondo un determinato formato standard (.exe, .bat, .jar, ecc.);
  • Un Sistema Operativo che gioca il ruolo di macchina universale e coordina tutte le funzioni della macchina calcolatrice.

È impossibile non cogliere le analogie e non ammirare il modo in cui Alan Turing è riuscito a formulare un linguaggio logico capace di adattarsi alle parole che legge formulate nel suo stesso linguaggio.

Turing, nel formulare questa struttura, si è voluto ispirare il più possibile all’essere umano, in particolare osservando i procedimenti mentali che effettua durante un calcolo matematico. Quando, per esempio, dobbiamo risolvere un’addizione, ciò che noi eseguiamo passo passo è: leggere il primo numero, memorizzare come stato mentale il primo numero, leggere il simbolo “+” e interpretarlo come la fine del primo numero, leggere il secondo numero e, associandolo con il primo numero memorizzato come stato mentale, produrre come risultato la somma finale.

In virtù delle ricerche di Turing, ogni linguaggio di programmazione utilizzato nella storia ha la caratteristica di essere Turing-completo, ovvero possiede termini di sintassi e di grammatica sufficienti a permettere la formulazione di ogni possibile algoritmo. E anche dopo decenni di ricerche e sviluppi, dopo molteplici evoluzioni dei linguaggi e dei meccanismi di astrazione, le idee di Turing restano il pilastro delle scienze informatiche.


L’immagine di copertina è tratta dal film The Imitation Game di Morten Tyldum (2014).

Annunci

Rispondi

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...