Category Archives: Python

Valutare XKCD con Windows? Si può fare!

nm0

Nel post precedente si valutava l’ipotesi che XKCD sia collegato a La Risposta, come –forse– un giorno grazie all’AI si riuscirà finalmente a provare, trovando –finalmente– La Domanda.
Nel post precedente (devo ricordarmi di non cominciare una frase nello stesso modo della precedente) eravamo in un ambiente adatto con tutti i tools che possono tornare utili disponibili e pronti fin da subito, anzi da prima (quando ero ggiovane ricordo che un giorno è arrivato UNIX (allora si scriveva così, tutto maiuscolo e bisognava dire che UNIX is a trademark of Bell Laboratories, Inc.)) ma come e cosa si può fare in ambienti meno friendly amichevoli. O –a volte– decisamente ostili, per esempio quello con la finestra storta, com’è già che si chiama?

Anche per loro ci sono strumenti [1] grazie a FOSS, come vedremo.
Oggi useremo Python, 3.x, costruendo il comando passo-passo.

x6

Fin qui niente di speciale, è una stringa. Per il nostro scopo possiamo usare list():

x7

Dalla lista c possiamo passare a quella dei valori ASCII (o Unicode, in questo caso coincidono) v.

x8

Lo so che non si devono fare cicli in questo modo [2] ma è provvisorio, solo per la costruzione.
Usiamo la funzione ord().
Abbiamo così la lista dei valori; troppo grossi però. Dovrebbe valere 1 per A, 2 per B e così via.
Beh, facile basta applicare un offset, questo:

x9

e riscrivere il loop precedente così:

x10

Non ci resta che fare la somma, via sum():

x11

OK! Adesso l’unione degli snippets [3] precedenti ed ecco:

x12

Resta un ultimo step: [4]

x13

Fatto! In fondo era semplice [5]😀


[1] Mi dice Sole (sì, è tornata) che non devo usare “tools”; e non fare i prulari.
[2] prima vennero per il GOTO ma non era per me, poi vennero per… (quasi-cit.).
[3] frammenti, mi dicono.
[4] passo. (Devo smetterla che si sta –come dire– potrebbe diventare pericoloso per me e per il ‘puter).
[5]
mom:mrgreen:

str2lst: omoiconicità in Python

timpo

Intanto la definizione della parola difficile che non sono nemmeno tanto sicuro ci sia in italiano: omoiconicità.
La Wiki (come farei senza? (auto-cit.)) dice:

In computer programming, homoiconicity (from the Greek words homo meaning the same and icon meaning representation) is a property of some programming languages in which the program structure is similar to its syntax, and therefore the program’s internal representation can be inferred by reading the text’s layout.

I linguaggi che vengono in mente prima di subito sono quelli della famiglia del Lisp ma non lo dico per non spaventare.

E poi anche perché mi serve con Python.
Forse non ho stackoverflato e googlato bene, ma in fondo è una cosa semplicissima:

s0

OK, funziona, da farci la funzione:

def str2lst(st):
    return eval(st)

s1

OK, ma visto che è così sintetica forse non serve, usare direttamente eval. Anche perché se uno proprio vuole (voglio? sì!) c’è lambda:

str2lst = lambda st: eval(st)

s2

OK!😀
Forse ne ho già parlato in passato ma non riesco a ritrovarlo. E i fatti di questi giorni mi hanno bloccato su questa funzione semplicissima. Non vorrei dire che sia tutta colpa di Trump ma insomma…:mrgreen:

Coconut – utilities e considerazioni conclusive – 13

super-metal

Proseguendo da qui oggi copio qui, dove si parla di utilities. E poi concludo (per adesso).

Syntax Highlighting
Si può fare con Sublime Text, Pygments o altri metodi ancora.
Interessa? Pygments mi sembra sexy; non fosse che sono vecchio e per via di quello che adesso racconto.

Si può usare Coconut?
Secondo me sì ma ci sono alcune issues da addressare questioni da affrontare:

  • Coconut è nuovo e (per quel che ne so) personale, sviluppato dal solo Evan Hubinger, rockz😀
  • sarebbe un altro linguaggio da imparare, sono già troppi;
  • per ragioni misteriose i linguaggi funzionali sono visti con diffidenza.

Illustro con un paio di esempi, spero indicativi.

c59

Quale delle due scritture è più naturale? Forse solo questione di abitudini ma…

Inoltre supponiamo che il codice Coconut sia contenuto nel file e.coco:

from math import exp
1 |> exp |> print

che compilo

c60

Il file risultante e.py è OK, nel senso che può essere eseguito

c61

ma è disastrosamente lungo e casinato

c62

Aprendolo e copiando le ultime due righe dentro Python (cosa che potrebbe capitare in caso di manutenzione, se si evita il file Coconut) si ottiene un codice eseguibile:

c63

quasi. Un caso più realistico (anche se sempre finto) è quello in cui il file .coco sia un modulo, come nel caso minimo val_const.coco:

from math import exp

def val_e():
    match t = 1 |> exp
    return t

che posso compilare e usare con Python:

c64

OK. Però, al solito il codice .py prodotto è lungo

c65

e –soprattutto– immodificabile all’interno di Python, per la manutenzione serve Coconut.

Quindi, in conclusione: Coconut mi piace, da monitorare, vedere se cresce. Per l’uso è da valutare all’interno del proprio ecosistema (cit.), è un altro linguaggio il cui apprendimento richiede risorse.
Mi è inoltre stato fatto notare che esistono progetti simili, chissà l’evoluzione… (visto che non cito Niels Bohr?)😀

:mrgreen:

Coconut – built-ins – 12

Coj9

Continuo da qui, oggi su built-ins che semplificano il codice, qui.

addpattern
Takes one argument that is a pattern-matching function, and returns a decorator that adds the patterns in the existing function to the new function being decorated, where the existing patterns are checked first, then the new. Equivalent to:

def addpattern(base_func):
    """Decorator to add a new case to 
       a pattern-matching function, 
       where the new case is checked last."""
    
    def pattern_adder(func):
        def add_pattern_func(*args, **kwargs):
            try:
                return base_func(*args, **kwargs)
            except MatchError:
                return func(*args, **kwargs)
        return add_pattern_func
    return pattern_adder

c48

cosa che con Python … ahemmmm, già😉

prepattern
Takes one argument that is a pattern-matching function, and returns a decorator that adds the patterns in the existing function to the new function being decorated, where the new patterns are checked first, then the existing. Equivalent to:

def prepattern(base_func):
    """Decorator to add a new case to
       a pattern-matching function, 
       where the new case is checked first."""
    def pattern_prepender(func):
        def pre_pattern_func(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except MatchError:
                return base_func(*args, **kwargs)
        return pre_pattern_func
    return pattern_prepender

c49

con Python –come già detto.

reduce
Coconut re-introduces Python 2’s reduce built-in, using the functools.reduce version.
Apply function of two arguments cumulatively to the items of sequence, from left to right, so as to reduce the sequence to a single value. For example, reduce((x, y) -> x+y, [1, 2, 3, 4, 5]) calculates ((((1+2)+3)+4)+5). The left argument, x, is the accumulated value and the right argument, y, is the update value from the sequence. If the optional initializer is present, it is placed before the items of the sequence in the calculation, and serves as a default when the sequence is empty. If initializer is not given and sequence contains only one item, the first item is returned.

c50

takewhile
Coconut provides itertools.takewhile as a built-in under the name takewhile.
takewhile(predicate, iterable)
Make an iterator that returns elements from the iterable as long as the predicate is true. Equivalent to:

def takewhile(predicate, iterable):
    # takewhile(lambda x: x<5, [1,4,6,4,1]) --> 1 4
    for x in iterable:
        if predicate(x):
            yield x
        else:
            break

L’esempio proposto mi da errore, forse dovuto alla versione😦

Coconut:
negatives = takewhile(numiter, (x) -> x<0)

Python:
import itertools
negatives = itertools.takewhile(numiter, lambda x: x<0)


dropwhile
Coconut provides itertools.dropwhile as a built-in under the name dropwhile.

dropwhile(predicate, iterable)
Make an iterator that drops elements from the iterable as long as the predicate is true; afterwards, returns every element. Note: the iterator does not produce any output until the predicate first becomes false, so it may have a lengthy start-up time. Equivalent to:

def dropwhile(predicate, iterable):
    # dropwhile(lambda x: x<5, [1,4,6,4,1]) --> 6 4 1
    iterable = iter(iterable)
    for x in iterable:
        if not predicate(x):
            yield x
            break
    for x in iterable:
        yield x

Come per il caso precedente ottengo un errore.

Coconut:
positives = dropwhile(numiter, (x) -> x<0)

Python:
import itertools
positives = itertools.dropwhile(numiter, lambda x: x<0)

tee
Coconut provides itertools.tee as a built-in under the name tee.
tee(iterable, n=2)
Return n independent iterators from a single iterable. Equivalent to:

def tee(iterable, n=2):
    it = iter(iterable)
    deques = [collections.deque() for i in range(n)]
    def gen(mydeque):
        while True:
            if not mydeque:             # when the local deque is empty
                newval = next(it)       # fetch a new value and
                for d in deques:        # load it to all the deques
                    d.append(newval)
            yield mydeque.popleft()
    return tuple(gen(d) for d in deques)

Once tee() has made a split, the original iterable should not be used anywhere else; otherwise, the iterable could get advanced without the tee objects being informed.

This itertool may require significant auxiliary storage (depending on how much temporary data needs to be stored). In general, if one iterator uses most or all of the data before another iterator starts, it is faster to use list() instead of tee().

c51

consume
Coconut provides the consume function to efficiently exhaust an iterator and thus perform any lazy evaluation contained within it. consume takes one optional argument, keep_last, that defaults to 0 and specifies how many, if any, items from the end to return as an iterable (None will keep all elements). Equivalent to:

def consume(iterable, keep_last=0):
    """Fully exhaust iterable and return the last keep_last elements."""
    return collections.deque(iterable, maxlen=keep_last) 
                                    # fastest way to exhaust an iterator

In the process of lazily applying operations to iterators, eventually a point is reached where evaluation of the iterator is necessary. To do this efficiently, Coconut provides the consume function, which will fully exhaust the iterator given to it.

c52

count
Coconut provides a modified version of itertools.count that supports in, normal slicing, optimized iterator slicing, count and index sequence methods, repr, and _start and _step attributes as a built-in under the name count.
count(start=0, step=1)
Make an iterator that returns evenly spaced values starting with number start. Often used as an argument to map() to generate consecutive data points. Also, used with zip() to add sequence numbers. Roughly equivalent to:

def count(start=0, step=1):
    # count(10) --> 10 11 12 13 14 ...
    # count(2.5, 0.5) -> 2.5 3.0 3.5 ...
    n = start
    while True:
        yield n
        n += step

c53

Verifica:

c53-1

In Python can’t be done quickly without Coconut’s iterator slicing, which requires many complicated pieces. The necessary definitions in Python can be found in the Coconut header.

map and zip
Coconut’s map and zip objects are enhanced versions of their Python equivalents that support normal slicing, optimized iterator slicing (through __coconut_is_lazy__), reversed, len, repr, and have added attributes which subclasses can make use of to get at the original arguments to the object (map supports _func and _iters attributes and zip supports the _iters attribute).

c54

In Python can’t be done without defining a custom map type.

datamaker
Coconut provides the datamaker function to allow direct access to the base constructor of data types created with the Coconut data statement. This is particularly useful when writing alternative constructors for data types by overwriting __new__. Equivalent to:

def datamaker(data_type):
    """Returns base data constructor of data_type."""
    return super(data_type, data_type).__new__$(data_type)

Coconut:

data trilen(h):
def __new__(cls, a, b):
return (a**2 + b**2)**0.5 |> datamaker(cls)

Python:

import collections
class trilen(collections.namedtuple("trilen", "h")):
    __slots__ = ()
    def __new__(cls, a, b):
        return super(cls, cls).__new__(cls, (a**2 + b**2)**0.5)


recursive

Coconut provides a recursive decorator to perform tail recursion optimization on a function written in a tail-recursive style, where it directly returns all calls to itself. Do not use this decorator on a function not written in a tail-recursive style or the function will likely break.

c55

La REPL visualizza male la riga “raise TypeError("the argument must be an integer >= 0")“.

In Python can’t be done without a long decorator definition. The full definition of the decorator in Python can be found in the Coconut header.

parallel_map
Coconut provides a parallel version of map under the name parallel_map. parallel_map makes use of multiple processes, and is therefore often much faster than map. Use of parallel_map requires concurrent.futures, which exits in the Python 3 standard library, but under Python 2 will require python -m pip install futures to function.
Because parallel_map uses multiple processes for its execution, it is necessary that all of its arguments be pickleable. Only objects defined at the module level, and not lambdas, objects defined inside of a function, or objects defined inside of the interpreter, are pickleable. Furthermore, on Windows, it is necessary that all calls to parallel_map occur inside of an if __name__ == "__main__" guard.

parallel_map(_func, *iterables_)

Equivalent to map(func, *iterables) except func is executed asynchronously and several calls to func may be made concurrently. If a call raises an exception, then that exception will be raised when its value is retrieved from the iterator.

c56

e

c57

MatchError
A MatchError is raised when a destructuring assignment statement fails, and thus MatchError is provided as a built-in for catching those errors. MatchError objects support two attributes, pattern, which is a string describing the failed pattern, and value, which is the object that failed to match that pattern.

:mrgreen:

Coconut – Istruzioni – 11

no-fun-allowed

Non so se si userà Coconut ma rockz😀 continuo da qui a copiare qui.

Istruzioni

Coconut supports significantly enhanced destructuring assignment, similar to Python’s tuple/list destructuring, but much more powerful. The syntax for Coconut’s destructuring assignment is

[match] <pattern> = <value> 

where <value> is any expression and <pattern> is defined by Coconut’s match statement. The match keyword at the beginning is optional, but is sometimes necessary to disambiguate destructuring assignment from normal assignment, which will always take precedence. Coconut’s destructuring assignment is equivalent to a match statement that follows the syntax:

match <pattern> in <value>:
    pass
else:
    err = MatchError(<error message>)
    err.pattern = "<pattern>"
    err.value = <value>
    raise err

If a destructuring assignment statement fails, then instead of continuing on as if a match block had failed, a MatchError object will be raised describing the failure.

c46

With Python can’t be done without a long series of checks in place of the destructuring assignment statement. See the compiled code for the Python syntax.

Decoratori
Unlike Python, which only supports a single variable or function call in a decorator, Coconut supports any expression.

L’esempio riportato non è completo e non ho trovato qualcosa di diverso da uno che seguirà prossimamente. Per cui riporto solo il codice senza eseguirlo.

Coconut:

@wrapper1 .. wrapper2 $(arg)
def func(x) = x**2

Python:

def wrapper(func):
    return wrapper1(wrapper2(arg, func))
@wrapper
def func(x):
    return x**2

Istruzioni else
Coconut supports the compound statements try, if, and match on the end of an else statement like any simple statement would be. This is most useful for mixing match and if statements together, but also allows for compound try statements.

Coconut:

try:
    unsafe_1()
except MyError:
    handle_1()
else: try:
    unsafe_2()
except MyError:
    handle_2()

Python:

try:
    unsafe_1()
except MyError:
    handle_1()
else:
    try:
        unsafe_2()
    except MyError:
        handle_2()

Istruzioni except
Python 3 requires that if multiple exceptions are to be caught, they must be placed inside of parentheses, so as to disallow Python 2’s use of a comma instead of as. Coconut allows commas in except statements to translate to catching multiple exceptions without the need for parentheses.

Coconut:

try:
    unsafe_func(arg)
except SyntaxError, ValueError as err:
    handle(err)

Python:

try:
    unsafe_func(arg)
except (SyntaxError, ValueError) as err:
    handle(err)


Lista di variabili

Coconut allows for the more elegant parenthetical continuation instead of the less elegant backslash continuation in import, del, global, and nonlocal statements.

c47

Codice passthrough
No, non so tradurlo (codice attraversante? orrendo!).
Coconut supports the ability to pass arbitrary code through the compiler without being touched, for compatibility with other variants of Python, such as Cython or Mython. Anything placed between \( and the corresponding close parenthesis will be passed through, as well as any line starting with \\, which will have the additional effect of allowing indentation under it.

Coconut:

\\cdef f(x):
    return x |> g

Python:

cdef f(x):
    return g(x)

:mrgreen:

Fare una REPL

phone-humour

L’altro giorno con GG si ragionava che certe operazioni ripetitive sarebbero semplificate usando una REPL, come quelle che uso di solito per Racket, Octave, Coconut, … E anche Python usato interattivamente anche se non si usa chiamarlo REPL è esattamente quella. Ma tra il dire e il fare…

La versione elementare è qualcosa come questa:

while read -p "> " st ; do
    echo $st
    if [[ $st == "Q" ]]; then
        exit 0
    fi
done

r0

Ma…

r1

non funzionano le frecce e i comandi di editing usuali (quelli che i giovani non conoscono, questi qui).

Aggiornamento: per l’edit della linea e l’uso delle frecce vedi il man di read e lo script with, qui.

La stessa cosa capita con Python:

#!/usr/bin/python3

while True:
    st = input('> ')
    print(st)
    if st.strip()[0] == 'Q': exit(0)

r2

Uhmmm… è un compito più impegnativo. Ma se provassimo a googlare?

Sì sorprese in quantità😀 come al solito spesso c’è qualche nerd da qualche parte che ci ha già pensato –e forse risolto😀
Ecco qualche esempio.

Ottimo Derick Bailey: Build Your Own App Specific REPL For Your NodeJS App con soluzioni per Ruby e NodeJS. Solo che andrebbe personalizzato e non sono i linguaggi preferiti (almeno non da entrambi).
Ancora più bella la soluzione di nodejitsu: How to create and use a custom REPL.

#!/usr/bin/node

var net = require("net"),
    repl = require("repl");

var mood = function () {
    var m = [ "^__^", "-___-;", ">.<", "" ];
    return m[Math.floor(Math.random()*m.length)];
};

//A remote node repl that you can telnet to!
net.createServer(function (socket) {
  var remote = repl.start("node::remote> ", socket);
  //Adding "mood" and "bonus" to the remote REPL's context.
  remote.context.mood = mood;
  remote.context.bonus = "UNLOCKED";
}).listen(5001);

console.log("Remote REPL started on port 5001.");

//A "local" node repl with a custom prompt
var local = repl.start("node::local> ");

// Exposing the function "mood" to the local REPL's context.
local.context.mood = mood;

r3

Albert Latacz ha la soluzione per Java: Java REPL – Java REPL is a simple Read-Eval-Print-Loop for Java language. Lo vedrà GG, prossimamente.

OK, finora abbiamo visto linguaggi non proprio miei (GG prossimamente, dopo le ferie, …) ma ecco Python, su Stack Overflow: How to implement a Python REPL that nicely handles asynchronous output?
Sembra interessante.
Il post fa riferimento a un modulo ad hoc, sclapp ma non risulta più attivo, benché presente (non all’URL indicato); non provato.
Con qualche aggiornamento essendo codice scritto per la versione 2.x, ecco r-so.py:

#!/usr/bin/python3

import readline
import threading

PROMPT = '> '

def interrupt():
    print(readline.get_line_buffer(), sep='', end='')

def cli():
    print('Interrupting cow -- moo!')
    while True:
        cli = str(input(PROMPT))
        print(cli)
        if cli.strip() == 'q!': exit(0)

if __name__ == '__main__':
    threading.Thread(target=cli).start()
    threading.Timer(2, interrupt).start()

r4

Sembra tutto OK; la riga print(cli) va sostituita con un case (se si usa Coconut) o un if colossale che è meglio mettere in una funzione. Da completare, prossimamente…
Però c’è anche questo: cmd – Create line-oriented command processors.
Il modulo cmd è tra quelli automaticamente installati con Python.

Da provare prima di subito; questo è l’esempio del post (r-cmd.py):

#!/usr/bin/python3

import cmd

class HelloWorld(cmd.Cmd):
    """Simple command processor example."""
    
    def do_greet(self, line):
        print("hello")
    
    def do_EOF(self, line):
        return True
    
if __name__ == '__main__':
    HelloWorld().cmdloop()

r5

Vediamo se ho capito, personalizzo (r-cmd-mod.py):

#!/usr/bin/python3

import cmd
import os

class HelloWorld(cmd.Cmd):
    """Simple command processor example."""
    
    def preloop(self):
        self.prompt = "$ > "
    
    def do_greet(self, line):
        print("hello")
    
    def do_EOF(self, line):
        print("")
        return True
    
    def do_mycmd(self, line):
        os.system("pwd;date")
        
if __name__ == '__main__':
    HelloWorld().cmdloop()

r6

😀 OK!

Conclusione
Si può fare, chissà se si farà, chissà se il mio giovane collaboratore über-nerd… Per adesso l’ho messo tra le cose da fare, quasi urgenti ma non urgenti per davvero😉

:mrgreen:

Coconut – Espressioni

lovelace

Ho fatto un po’ di prove e Coconut funziona😀
Deve crescere ma mi sa che lo userò per compiti particolari (p.es.: case) intanto continuo a studiarlo, copiando qui.

Lazy lists
Coconut supports the creation of lazy lists, where the contents in the list will be treated as an iterator and not evaluated until they are needed. Lazy lists can be created in Coconut simply by simply surrounding a comma-seperated list of items with (| and |) (so-called “banana brackets”) instead of [ and ] for a list or ( and ) for a tuple.

Lazy lists use the same machinery as iterator chaining to make themselves lazy, and thus the lazy list (| x, y |) is equivalent to the iterator chaining expression (x,) :: (y,), although the lazy list won’t construct the intermediate tuples.

Lazy lists, where sequences are only evaluated when their contents are requested, are a mainstay of functional programming, allowing for dynamic evaluation of the list’s contents.

c40

In Python can’t be done without a complicated iterator comprehension in place of the lazy list. See the compiled code for the Python syntax.
Ecco un altro caso in cui torna utile😀

Applicazione parziale implicita
Coconut supports a number of different syntactical aliases for common partial application use cases. These are:

.attr         =>  operator.attrgetter("attr")
.method(args) =>  operator.methodcaller("method", args)
obj.          =>  getattr$(obj)
func$         =>  ($)$(func)
seq[]         =>  operator.__getitem__$(seq)
iter$[]       =>  # the equivalent of seq[] for iterators

c41

Vuoi vedere che manca un modulo…

c42

OK, come previsto😀

Set Literals
Coconut allows an optional s to be prepended in front of Python set literals. While in most cases this does nothing, in the case of the empty set it lets Coconut know that it is an empty set and not an empty dictionary. Additionally, an f is also supported, in which case a Python frozenset will be generated instead of a normal set.

c43

Imaginary Literals
In addition to Python’s <num>j or <num>J notation for imaginary literals, Coconut also supports <num>i or <num>I, to make imaginary literals more readable if used in a mathematical context.

Imaginary literals are described by the following lexical definitions:
imagnumber ::= (floatnumber | intpart) ("j" | "J" | "i" | "I")

An imaginary literal yields a complex number with a real part of 0.0. Complex numbers are represented as a pair of floating point numbers and have the same restrictions on their range. To create a complex number with a nonzero real part, add a floating point number to it, e.g., (3+4i). Some examples of imaginary literals:
3.14i   10.i    10i     .001i   1e100i  3.14e-10i

c44

Underscore Separators
Coconut allows for one underscore between digits and after base specifiers in numeric literals. These underscores are ignored and should only be used to increase code readability. Comodo, pochi linguaggi lo usano, p.es. Ada.

c45

:mrgreen:

 

Il Fortran iniziale, I/O, FORMAT

wo-the-wizard

Il titolo è fuorviante, riassumo una conversazione con un collega dei tempi antichi riguardo al post Lo sviluppo iniziale dei linguaggi di programmazione.
Naturalmente riguarda il Fortran l’unico linguaggio che c’era sul ‘puter che usavamo. Il programma postato da Knuth e Trabb Pardo (K&T) è per la versione 0 (zero), forse solo virtuale. La prima versione con cui ho avuto a che fare è la IV, anzi un’evoluzione compatibile con la 66 ma c’era codice scritto per la versione II (1958), trasferito da schede a nastri o dischi o semplicemente ricopiato dal listato.
In ogni caso il programma postato da K&T deve essere aggiornato (ehi! 50 anni!): non solo le funzioni non hanno (dalla preistoria) il nome che deve terminare con F ma non ho nemmeno un lettore di schede😦
E non saprei nemmeno trovare le schede😦 e la perforatrice😦

forig

Però il programma prevede la lettura di dati formattati in modo preciso, cosa che da terminale non è agevole (bisogna essere proprio pistini) ma si può fare un formattatore, come i millemila come si usava una volta.

Ah! un altro problema: la gestione dei file: allora si aprivano da OS, il programma lo dava per scontato e alla fine si chiudevano, sempre da OS. I comandi Prime erano rispettivamente OPEN seguito dai parametri che non ricordo ma roba tipo 1 1 (unità 5 in lettura [aggiornamento: il secondo parametro è da verificare, probamilente non come pensavo]) e CLOSE 1 (unità 5); siccome di solito si dovevano chiudere più unità c’era il comodo CLOSE ALL. Su Prime (come con il DEC) i comandi potevano essere abbreviati, nel nostro caso al posto di OPEN bastava O, era il comando più importante iniziante con quella lettera, e C stava per CLOSE.
Quindi, se ricordo bene, il mio command-file per l’esecuzione del programma FMT sarebbe stato così:

O DATI-FREE 1 1
O DATI 2 2
SEG FMT
C ALL

L’istruzione di lancio SEG FMT valeva nell’ipotesi che il programma fosse stato compilato per la versione segmentata (prevista per i programmi grossi) usata (a sproposito) abitualmente. Però se uno era razionale vedeva che bastava la versione normale, anche più veloce quindi la riga sarebbe stata RUN FMT, RUN abbreviabile in R. OK, mode nostalgia OFF.

La versione corrente usa le normali istruzioni OPEN e CLOSE, non disponibili allora. Per evidenziare il nuovo uso il minuscolo, adesso equivalente al maiuscolo, allora vietato.

Ecco fmt.f

C FMT legge in free-format e scrive formattato

      DIMENSION A(11)
      
      open(1, file='dati-free')
      READ(1, *) A
      close(1)
      
      open(2, file='dati')
      WRITE(2, 2) A
      close(2)
2     FORMAT(6F12.4)

      END

Aggiornamento: per il Prime le prime 4 unità di I/O erano predefinite e riservate per cui avrei dovuto usare numeri più alti, tipicamente 5 e 6 al posto di 1 in OPEN e 2 in WRITE.

E questo è il file di dati dati-free

1 10 100 1000 10000 98765 987654
987654.3 2.7818 3.1415 -42

Compilo ed eseguo

f0

ottenendo il file dati

      1.0000     10.0000    100.0000   1000.0000  10000.0000  98765.0000
 987654.0000 987654.3125      2.7818      3.1415    -42.0000

Uh! visto il secondo dato della seconda riga? è 987654.3125 invece del previsto 987654.3000😳 ma il formato REAL*4 (quello usato per le variabili inizianti con una lettera fuori dell’intervallo [I-N] riservato agli interi) garantisce 7-8 cifre significative.

Per essere proprio sicuri-sicuri si può fare la verifica, con il file verifica.f

C VERIFICA

      DIMENSION A(11)
      
      open(1, file='dati')
      READ(1, 2) A
      close(1)
2     FORMAT(6F12.4)

      DO 3 I = 1, 11
        PRINT *, A(I)
3     CONTINUE     

      END

f1

OK, ci siamo. A questo punto torno al programma di K&P, opportunamente aggiornato (tpk.f).

C     THE TPK ALGORHTM, FORTRAN STYLE
*     aggiornato, modifiche in minuscolo

      FUN(T) = SQRT(ABS(T)) + 5.0**3
      DIMENSION A(11)
1     FORMAT(6F12.4)
      open(1, file = 'dati') 
      READ(1, 1) A
      close(1)
      DO 10 J =1, 11
      I = 11 - J
      Y = FUN(A(I+1))
      IF(400.0 - Y) 4, 8, 8
4     write(*, 5) I
5     FORMAT(I10, 10H TOO LARGE)
      GO TO 10
8     write(*, 9) I, Y
9     FORMAT(I10, F12.7)
10    CONTINUE
      STOP 52525
      end

f2

OK😀

C’è ancora una cosa emersa ieri: le funzioni, quando non ci sono si fanno. A dire tutta la verità i fortrainers preferivano –di gran lunga– le SUBROUTINEs ma questo sarebbe un altro rant, lunghissimissimo😉

Era tipico di IBM fornire funzioni che non si avevano (no, niente nomi). Per gioco supponiamo non fossero definite ABS e SQRT.
La prima è banale (e lasciata come esercizio) mentre la seconda è leggermente più impegnativa. Siccome il mondo è vario da adesso in poi continuo con Python 3.x, il Basic dei nostri giorni.

Invece di limitarci alla radice quadrata conviene probabilmente essere più generali; che ne dite di usare i logaritmi? OK, la Wiki (come faremmo senza?) ci dice tutto. Illo tempore probabilmente avrei cercato sul Dwight –hey! c’è online–, c’è il capitolo Logarithmic Functions, p.130
log-x
Per l’esponenziale c’è Exponential Functions a p.125

exp-x

Quindi ecco myfunc.py:

# modulo per Python 3.x; 
# per 2.x importare division from tuture

my_e = 2.71828182845904523536 

def my_log(x):
    r = (x - 1) / (x + 1)
    d = r
    v = d
    c = 1
    while d > 1e-8:
        c += 2
        t = 1
        for i in range(1, c + 1):
            t *= r
        d = 1/c * t
        v += d

    return round(2 * v, 8)

def my_exp(x):
    fact = 1
    t = x/fact
    e = 1 + t
    num = x
    c = 1
    while t > 1.e-8:
        c += 1
        fact *= c
        num *= x
        t = num / fact
        e += t
    st = str(e)
    ppoint = st.index(".")
    if ppoint < 8:
        e = round(e, 8 - ppoint)
    else:
        e = round(e, 1) 

    return e
    
def my_sqrt(x):
    return my_exp(1/2 * my_log(x))

py0

:mrgreen:

Una risposta & una domanda

woz

Una risposta a Jilla, forse se lo saranno chiesto anche altri: Coconut è nuovo ma promette bene. E l’uso che immediatamente viene in mente è quello di creare moduli con dentro le costanti e le funzioni che si intende usare, visto che permette di scrivere chiaramente e sinteticamente cose che con Python sono meno immediate, p.es. case.
Ecco un esempio (banalissimo, certamente nessuno scriverebbe cose così per davvero) di quali sono le mie intenzioni.

Il modulo coco_module.coco:

risposta = 42

def ciao(nome):
    print("Ehi", nome, "ciao!")

def doppio(n):
    return 2 * n

Che compilo ottenendo il modulo Python

r0

Non importa che coco_module.py sia lungo 298 righe, non devo editarlo, solo usarlo, nello script uso_c_m.py:

from coco_module import *

ciao("Juhan")
print(risposta, doppio(doppio(doppio(risposta))))

r1

Ovviamente –come già detto– quando il gioco si fa duro (inizio-cit.).

OK, lo ammetto: Coconut mi piace per i suoi aspetti funzionali che adesso pare siano trendyassay, quasi fossero pokémons. Forse perché contemporaneamente sto vedendo quell’altro linguaggio, di cui al momento non ricordo il nome, molto più tradizionale (nato come alternativa semplice del Fortran).


Siccome ho risposto, spero esaurientemente, alla domanda fattami ne avrei una anch’io (me). Chissà se…
Viene da un tweet, Why Linux sucks and will never compete with Windows or OSX.

Non so chi l’ha retwittato ma ho voluto vedere cos’è che non va con Linux.
Inizialmente ho classificato non tanto bene il post, l’autore del post, il titolare del blog, il retwittatore &co. poi però –in modo non esattamente razionale– ci ho rimuginato su. Non ho capito se l’autore sta lollando o cosa. Non ho capito cosa non gli va di Linux, sa usarlo, lo usa da tempo. Viene anche il dubbio che sia al servizio di NWO o Bilderberg o anche peggio (M$).

Sperando di non fargli pubblicità (segue 3 ed è seguito da 4 ma ha un blog) la mia domanda è: che dire del tipo e del tipo che ha linkato?

:mrgreen:

Coconut – keywords II

handshake

Continuo con le keywords, da qui, copiando qui.

case
Coconut’s case statement is an extension of Coconut’s match statement for performing multiple match statements against the same value, where only one of them should succeed. Unlike lone match statements, only one match statement inside of a case block will ever succeed, and thus more general matches should be put below more specific ones.

Each pattern in a case block is checked until a match is found, and then the corresponding body is executed, and the case block terminated. The syntax for case blocks is

case <value>:
    match <pattern> [if <cond>]:
        <body>
    match <pattern> [if <cond>]:
        <body>
    ...
[else:
    <body>]

where <pattern> is any match pattern, <value> is the item to match against, <cond> is an optional additional check, and <body> is simply code that is executed if the header above it succeeds. Note the absence of an in in the match statements: that’s because the <value> in case <value> is taking its place.

c36

In Python can’t be done without a long series of checks for each match statement. See the compiled code for the Python syntax.

c37

Al solito codice difficile da leggere, peraltro OK:

c38

Backslash-Escaping
In Coconut, the keywords data, match, case, async (keyword in Python 3.5), and await (keyword in Python 3.5) are also valid variable names. While Coconut can disambiguate these two use cases, when using one of these keywords as a variable name, a backslash is allowed in front to be explicit about using a keyword as a variable name.

c39

Variabili riservate
In Coconut, all variable names starting with _coconut are reserved. The Coconut compiler will modify and reference these variables with the assumption that the code being compiled does not modify them in any way. If your code does modify any such variables, your code is unlikely to work properly.

:mrgreen: