Perché Haskell non ha una funzione 'format' per l'interpolazione delle stringhe?

6

Sto provando a utilizzare Shake e mi sono imbattuto nel seguente problema: non esiste un modo facile e conveniente per interpolare una stringa. Conosco Text.Printf - non è quello che sto cercando. La sintassi di interpolazione di cui sto parlando è così:

(Fai)

HEADERS_DIR := /some/path/to/dir

CFLAGS := "-g -I$(HEADERS_DIR) -O2"

(Python)

headers_dir = "/some/path/to/dir"

cflags = "-g -I{headers_dir} -O2".format(**locals())

E ora confronta questo con la possibile soluzione di Haskell. In primo luogo:

$ cabal install interpolatedstring-perl6
$ ghci -XExtendedDefaultRules -XQuasiQuotes

E poi:

> import Text.InterpolatedString.Perl6 (qq)
> let headers_dir = "/path/to/some/dir"
> [qq| -g -I$headers_dir -O2 |] :: String

Mentre penso che Make vada forse un passo troppo lontano nella sua impazienza di interpolare anche quando non è stato chiesto, mi chiedo perché Haskell non abbia una funzione format come fa Python. Potrebbe analizzare la stringa fornita e tirare il valore con lo stesso nome di riferimento nel modello:

let headers_dir = "/path/to/some/dir"
format "-g -I$headers_dir -O2"

C'è una ragione specifica per cui non è implementata, oppure tutti sono contenti della verbosità di Text.Printf e / o della lunga configurazione delle librerie di interpolazione?

Aggiornamento : molte persone interpretano erroneamente la domanda come una domanda sulla formattazione generale delle stringhe, con possibilità di specifiche di precisione in caso di numeri interi, ecc. Gli esempi forniti dimostrano un caso specifico di interpolazione, che è solo "sostituisci il risultato di show a nel luogo del nome". Permette una sintassi più semplice, e non usa una funzione variadica di per sé.

    
posta Michael Pankov 24.01.2014 - 15:12
fonte

5 risposte

3

Sospetto che sia fatto come quasiquoting perché questo interpolerà la stringa al momento della compilazione e, data la natura pura delle funzioni in Haskell, ciò è possibile mentre altre lingue mancano di tale capacità a causa della loro natura impura.

Pensaci, gli altri linguaggi devono farlo ogni volta durante il runtime, che sarà molto più lento del tempo di compilazione una volta e fatto un'interpolazione quasi citata.

Se vuoi farlo in fase di esecuzione in modo esplicito, dovresti essere in grado di fare alcune semplici astrazioni che sfruttano le stringhe di Haskell che sono elenchi, oppure potresti creare una struttura di dati diversa che è simile abbastanza facilmente - ma vorrei fare il approccio quasi-quotato più efficiente se lo facessi in qualsiasi codice mi interessasse veramente.

Detto questo, ho trovato su Hackage il pacchetto Data.Text.Format che sembra eseguire la sostituzione in stile C # piuttosto semplice, ecco una risposta che mostra un esempio su SO: Formattazione delle stringhe in Haskell - sebbene come notato da Bryan O'Sullivan e altri su quella domanda che risponde a un pacchetto obsoleto e ce n'è una nuova che Bryan ha creato (suppongo che il pacchetto Data.Text.Format sia il suo nuovo che dovrebbe essere usato) quindi l'uso potrebbe essere leggermente diverso da quello in SO, anche se sembra abbastanza simile.

    
risposta data 24.01.2014 - 17:26
fonte
1

Il miglior approccio tipologico che posso offrirti è la libreria formatting

{-# LANGUAGE OverloadedStrings #-}

import Formatting (format, (%))
import Formatting.ShortFormatters (t) 

headers_dir = "/path/to/some/dir"

example = format ("-g -I" % t % " -O2") headers_dir

GHCi> example 
"-g -I/path/to/some/dir -O2"
    
risposta data 24.01.2014 - 19:55
fonte
1

aggiornato dopo l'aggiornamento della domanda

Sento che la versione python:

"-g -I{headers_dir} -O2".format(**locals())

è un abuso della lingua. Quindi non direi che Python offre realmente l'interpolazione delle variabili locali nelle stringhe. In effetti, poche lingue ce l'hanno.

La risposta a why language X doesn't have feature Y spesso si riduce a dire che i progettisti non pensavano che ne valesse la pena. Nel caso di interpolazione di variabili locali in stringhe, è molto una cosa di nicchia usata in linguaggi focalizzati su script a riga di comando. Quale Haskell non lo è. Il fatto che tu possa farlo in Python viene solo dalle (anche?) Potenti possibilità di riflessione del linguaggio.

Ora perché Text.InterpolatedString.Perl6 è così complesso da usare? Si basa su quasiquotations, che non fa parte del linguaggio haskell. È un'estensione di linguaggio ghc, quindi devi dichiararne l'uso da qualche parte. Se escludi l'installazione della libreria & la dichiarazione di estensione del linguaggio, il suo utilizzo non è molto più complesso che negli altri esempi ed è più sicuro.

    
risposta data 24.01.2014 - 18:01
fonte
1

Cosa c'è di sbagliato con quasiquoting? Controlla Shakespeare (come menzionato nei commenti):

{-# LANGUAGE QuasiQuotes #-}
import Text.Shakespeare.Text
import Data.Text

runtimeInterpolatedString :: (ToText a, ToText b, ToText c) => a -> b -> c -> Text
runtimeInterpolatedString a b c = [lt|There once was #{a} that #{b} when #{c}.|]
    
risposta data 29.01.2014 - 04:14
fonte
1

In Python: il linguaggio in realtà specifica che le variabili possono essere referenziate per nome in fase di runtime. In Haskell: i nomi di tutto tranne i collegamenti di livello superiore tendono a essere cancellati durante la compilazione e sostituiti con riferimenti numerici.

Nel tuo esempio: headers_dir = "/path/to/some/dir" diventa qualcosa di più simile a 0x09039dc0 = "/path/to/some/dir" nel momento in cui il codice viene effettivamente eseguito. Ciò significa che qualsiasi riferimento a headers_dir deve essere sostituito dal riferimento numerico al momento della compilazione, che è quello per cui è stato utilizzato il quasiquoter.

Senza usare quasiquoters o altre parti di Template Haskell; dovresti fare qualcosa per conservare manualmente i nomi delle variabili, come mettere i valori in una mappa.

    
risposta data 02.06.2015 - 10:38
fonte

Leggi altre domande sui tag