Perché non più lingue hanno la possibilità di confrontare un valore con più di un altro valore? [chiuso]

10

Considera quanto segue:

if(a == b or c)

Nella maggior parte delle lingue, questo dovrebbe essere scritto come:

if(a == b or a == c)

che è leggermente macchinoso e ripete informazioni.

So che la mia sintassi di esempio sopra è leggermente goffa, ma sono sicuro che ci sono modi migliori per trasmettere l'idea.

Perché non lo offrono più lingue? Ci sono problemi di prestazioni o di sintassi?

    
posta Zeroth 01.05.2014 - 20:11
fonte

12 risposte

24

Il problema della sintassi è che richiede la sintassi.

Qualunque sintassi della tua lingua, le persone che usano la lingua devono impararla. Altrimenti corrono il rischio di vedere il codice e di non sapere cosa fa. Pertanto è generalmente considerato una buona cosa se una lingua ha una sintassi semplice che gestisce in modo pulito molti casi.

Nel tuo esempio specifico, stai provando a prendere un operatore infisso (una funzione che accetta due argomenti ma è scritta Argument1 Operator Argument2 ) e prova ad estenderla a più argomenti. Ciò non funziona in modo molto pulito perché l'intero punto degli operatori infissi, nella misura in cui ce n'è uno, è quello di mettere l'operatore giusto tra i 2 argomenti. L'estensione a (Argument1 Operator Argument2 MagicallyClearSymbol Argument3...) non sembra aggiungere molta chiarezza su Equals(Arg1,Arg2,...) . Infix è anche usato tipicamente per emulare convenzioni matematiche con cui le persone hanno familiarità, il che non sarebbe vero per una sintassi alternativa.

Non ci sarebbero particolari problemi di prestazioni associati alla tua idea, a parte il fatto che il parser dovrebbe gestire una grammatica con un'altra regola di produzione o due, il che potrebbe avere un leggero effetto sulla velocità di analisi. Questo potrebbe fare la differenza per un linguaggio compilato o interpretato dal JIT, ma probabilmente non è una grande differenza.

Il problema più grande con l'idea è solo che rendere molti casi speciali in una lingua tende a essere una cattiva idea .

    
risposta data 01.05.2014 - 21:38
fonte
6

Perché è un non-problema, e risolverlo comporta sostanzialmente zero benefici, ma implementarlo porta a costi non zero.

Le funzioni esistenti basate sull'intervallo e tali che praticamente tutte le lingue offrono possono funzionare perfettamente in questa situazione se si ridimensionano a una dimensione in cui a == b || a == c non la taglierà.

    
risposta data 01.05.2014 - 20:50
fonte
6

Alcune lingue hanno tali caratteristiche. Per esempio. in Perl6 possiamo usare Junctions , che sono "superposizioni" di due valori:

if $a == any($b, $c) {
    say "yes";
}

# syntactic sugar for the above
if $a == $b | $c {
    say "yes";
}

Le giunzioni ci consentono di esprimere operazioni su un insieme di dati in modo abbastanza succinto, simile al modo in cui le operazioni scalari distribuiscono su raccolte in alcune lingue. Per esempio. usando Python con numpy, il confronto può essere distribuito su tutti i valori:

import numpy as np
2 == np.array([1, 2, 3])
#=> np.array([False, True, False], dtype=np.bool)
(2 == np.array([1, 2, 3])).any()
#=> True

Tuttavia, questo funziona solo per i tipi primitivi selezionati.

Perché le giunzioni sono problematiche? Poiché le operazioni su un nodo distribuiscono sui valori contenuti, l'oggetto di giunzione stesso si comporta come un proxy per le chiamate al metodo: è in grado di gestire alcuni sistemi di tipo oltre alla digitazione anatra.

I tipi di problemi di sistema possono essere evitati se tali giunzioni sono consentite solo come speciale sintassi attorno agli operatori di confronto. Ma in questo caso, sono limitati così tanto da non aggiungere un valore sufficiente per essere aggiunti a qualsiasi linguaggio sano. Lo stesso comportamento potrebbe essere espresso utilizzando le operazioni di set o l'ortografia di tutti i confronti manualmente, e la maggior parte delle lingue non crede nell'aggiunta della sintassi ridondante se esiste già una soluzione perfettamente soddisfacente.

    
risposta data 01.05.2014 - 20:25
fonte
2

Nelle lingue con macro, è facile aggiungere qualcosa del genere se non è già lì. Considera Racket

(define-syntax-rule (equal-any? a b ...)
  (or (equal? a b) ...))
(equal-any? "a" "b" "a")
> #t

In altre lingue senza metaprogrammazione, forse puoi riformularlo come se fosse impostato / elenco il controllo dell'appartenenza:

if a ∈ {b, c}
    
risposta data 01.05.2014 - 20:23
fonte
2

In alcune lingue (popolari) == operator non è transitivo. Ad esempio in JavaScript 0 è uguale a '' e '0' , ma '' e '0' non sono uguali tra loro. Più di questi capricci in PHP.

Significa che a == b == c aggiungerebbe un'altra ambiguità, perché potrebbe produrre un risultato diverso a seconda che sia interpretato come (a == b) & (a == c) o (a == b) & (a == c) & (b == c) .

    
risposta data 02.05.2014 - 11:10
fonte
2

Nella maggior parte delle lingue, questo dovrebbe essere banalmente realizzabile scrivendo una funzione In , quindi perché farne parte del linguaggio attuale?

Linq, ad esempio, ha Contains() .

Bene, per tutti voi pedanti, ecco la mia implementazione in C #:

public static bool In<T>(this T obj, params T[] values)
{
    for(int i=0; i < values.Length; i++)
    {
        if (object.Equals(obj, values[i]))
            return true;
    }
    return false;
}
    
risposta data 01.05.2014 - 20:47
fonte
1

"if (a == b o c)" funziona nella maggior parte delle lingue: se a == b o se c non è negativo, nullo o pari a zero.

Lamentarsi che sia prolisso non coglie il punto: non si dovrebbero accumulare una dozzina di cose in un condizionale. Se è necessario confrontare un valore con un numero arbitrario di altri valori, quindi creare una subroutine.

    
risposta data 01.05.2014 - 21:13
fonte
1

Di solito, vuoi mantenere la sintassi al minimo e invece consentire che tali costrutti siano definiti nella lingua stessa.

Ad esempio, in Haskell puoi convertire qualsiasi funzione con due o più argomenti in un operatore infisso usando i backtick. Questo ti permette di scrivere:

if a 'elem' [b, c] then ... else ...

dove elem è solo una normale funzione che prende due argomenti - un valore e un elenco di valori - e controlla se il primo è un elemento del secondo.

Che cosa succede se si desidera utilizzare and anziché or ? In Haskell, puoi semplicemente usare quanto segue invece di aspettare che il fornitore del compilatore implementa una nuova funzione:

 if all (== a) [b, c] then ... else ...
    
risposta data 01.05.2014 - 22:57
fonte
1

Alcune lingue offrono questo - in una certa misura.

Forse non come esempio specifico , ma prendi per esempio una linea Python:

def minmax(min, max):
    def answer(value):
        return max > value > min
    return answer

inbounds = minmax(5, 15)
inbounds(7) ##returns True
inbounds(3) ##returns False
inbounds(18) ##returns False

Quindi, alcune lingue vanno bene con confronti multipli, a patto che tu la stia esprimendo correttamente.

Sfortunatamente, non funziona come ti aspetteresti per i confronti.

>>> def foo(a, b):
...     def answer(value):
...         return value == a or b
...     return answer
... 
>>> tester = foo(2, 4)
>>> tester(3)
4
>>> tester(2)
True
>>> tester(4)
4
>>> 

"Che cosa significa restituisce True o 4?" - il noleggio dopo di te

Una soluzione in questo caso, almeno con Python, è di usarla in modo leggermente diverso:

>>> def bar(a, b):
...     def ans(val):
...             return val == a or val == b
...     return ans
... 
>>> this = bar(4, 10)
>>> this(5)
False
>>> this(4)
True
>>> this(10)
True
>>> this(9)
False
>>> 

EDIT: Quanto segue farebbe anche qualcosa di simile, sempre in Python ...

>>> def bar(a, b):
...     def answer(val):
...             return val in (a, b)
...     return answer
... 
>>> this = bar(3, 5)
>>> this(3)
True
>>> this(4)
False
>>> this(5)
True
>>> 

Quindi, qualunque sia la lingua che stai usando, potrebbe non essere impossibile farlo, solo che devi prima dare un'occhiata più da vicino a come la logica effettivamente funziona. In genere si tratta solo di sapere cosa stai "chiedendo" effettivamente alla lingua per dirti.

    
risposta data 02.05.2014 - 00:23
fonte
1

Il metodo indexOf, utilizzato su una matrice, che ha tutte le lingue, consente di confrontare un valore con molti altri, quindi suppongo che un operatore speciale non abbia molto senso.

In javascript che scriverebbe:

if ( [b, c].indexOf(a) != -1 ) { ....  }
    
risposta data 02.05.2014 - 13:41
fonte
0

Chiedi perché non possiamo farlo: if(a == b or c)

Python lo fa in modo molto efficiente, in effetti, in modo più efficiente con set :

if a in set([b, c]):
    then_do_this()

Per i test di appartenenza, 'set' controlla che gli hash dell'elemento siano gli stessi e solo poi li confronti per l'uguaglianza, quindi gli elementi, be c, devono essere lavabili, altrimenti una lista si confronta direttamente per l'uguaglianza:

if a in [b, c]:
    then_do_this()
    
risposta data 02.05.2014 - 06:06
fonte
0

I linguaggi in stile APL consentono di confrontare uno scalare con ciascun elemento in un vettore in un'unica operazione. Questo produce un vettore booleano. Per esempio, mi piacerebbe promuovere spudoratamente il mio calcolatore apl minimamente caratterizzato, inca ( interprete online ).

   a<5
5 
   b<4
4 
   c<5
5 
   a=b c
0 1 

Per ridurlo a un singolo valore, possiamo fare un inclusivo o sommando e controllando per diverso da zero.

   0!+/a=b c
1 
   c<6
6 
   0!+/a=b c
0

Quindi, come dicono le altre risposte, il problema è la sintassi. In una certa misura, le soluzioni di sintassi sono state trovate, a un costo forse enorme dell'apprendimento del paradigma dell'array.

    
risposta data 02.05.2014 - 09:01
fonte