15

Quali lingue che non sono solo funzionali hanno dati algebriche tipi (o qualcosa di simile) e pattern matching? Sono anche interessato a linguaggi multi-paradigma - So che OCaml e F # sono dialetti ML con OO aggiunto, in modo che ereditano la tipi di dati algebrici da ML.Tipi di dati algebrici al di fuori delle lingue funzionali?

Possono essere emulati utilizzando enum se union s (come in C, C++, ... altro?), Ma questo diventa presto ingombrante e brutto e il compilatore non può avvisarti se si dimentica un caso in pattern matching o (molto più propable, e molto più pericoloso) quando si accede l'unione "in modo sbagliato", cioè si chiede per un campo di un valore Left quando in realtà è un valore Right (quello che si ottiene, allora è una reinterpretazione senza significato dei bit che si trovano lì).

Ho sentito dire che Pascal has something like tagged unions e Cyclone language supporta anche i collegamenti codificati. Wikipedia menziona anche Ada e Algol. Altre lingue?

(Nel caso in cui non avete mai sentito parlare di tipi di dati algebrici, è possibile leggere an Answer to "What is 'Pattern Matching' in functional languages?" per un'eccellente introduzione).

risposta

13

In Scala, di solito si utilizza case class per emulare i tipi di dati algebrici come si trovano nei linguaggi funzionali true-blue come ML e Haskell.

Ad esempio seguente codice F # (tratta da here):

type Shape = 
| Circle of float 
| EquilateralTriangle of double 
| Square of double 
| Rectangle of double * double 

let area myShape = 
    match myShape with 
    | Circle radius -> Math.PI * radius * radius 
    | EquilateralTriangle s -> (sqrt 3.0)/4.0 * s * s 
    | Square s -> s * s 
    | Rectangle (h, w) -> h * w 

possono essere approssimativamente tradotto a Scala come segue:

sealed abstract class Shape 
case class Circle(radius: Float) extends Shape 
case class EquilateralTriangle(side: Double) extends Shape 
case class Square(side: Double) extends Shape 
case class Rectangle(height: Double, width: Double) extends Shape 

def area(myShape: Shape) = myShape match { 
    case Circle(radius) => math.Pi * radius * radius 
    case EquilateralTriangle(s) => math.sqrt(3.0)/4.0 * s * s 
    case Square(s) => s * s 
    case Rectangle(h, w) => h * w 
} 

Il sealed parola sopra viene utilizzato per avere il compilatore segnala nel caso in cui si dimentichi qualsiasi case nell'espressione match.

6

Erlang ha un sistema di tipo dinamico, in modo che non fornisce alcuna delle garanzie che citi, ma il codice Erlang tende a guardare come il prodotto di un sistema di tipo algebrico:

count([]) -> 0; 
count([H|T]) -> 1 + count(T). 

length({rect, X, Y}) -> math:sqrt(X*X + Y*Y); 
length({polar, R, _A}) -> R. 
8

La programmazione logica la lingua Mercury li chiama discriminated unions. Il linguaggio vincolo CHR, incorporato in Prolog, has them troppo, ma ci sono del tutto opzionali, termini Prolog generale è il tipo predefinito.

+0

Grazie - Non ho idea di linguaggi logici, in modo da propably non avrei imparato questo io stesso. – delnan

+0

Entrambi sono linguaggi di ricerca. La comunità LP ha preso in prestito molto dai suoi cugini FP. –

10

Nella lingua Mozilla Rust, i tipi di dati algebrici e la corrispondenza dei modelli sono concetti importanti. Anche la sintassi è abbastanza carina. Si consideri il seguente programma semplice:

static PI: f32 = 3.14159; 

enum Shape { 
    Circle(f32), 
    Rectangle(f32, f32), 
    Point 
} 

fn area(shape: Shape) -> f32 { 
    match shape { 
     Point     => 0.0 
     Circle(radius)   => PI * radius * radius, 
     Rectangle(width, height) => width * height, 
    } 
} 

fn main() { 
    let radius = 4.0; 
    let circle = Circle(radius); 
    let area = area(circle); 
    println!("The area of a circle with radius {} is {}", radius, area); 
} 
+1

Anche la sintassi è abbastanza buona, sì, tranne l'insalata di parentesi graffe e il punto e virgola. – Ingo

+8

Le parentesi graffe sono fantastiche. – Malcolm

+0

@Malcolm Voglio ridimensionare il tuo commento;) --- raramente è un disturbo eccessivo utile, le parentesi non sono nemmeno informative su quale blocco chiudono! Il vecchio stile di if..fi o do..od o beginX ... endX è almeno informativo, con le parentesi tendiamo a finire con una scala che occupa spazio ed è del tutto inutile per la leggibilità. –

3

penso che Whiley sarebbe qualificarsi. Whiley ha tipi di record (.ie. Prodotto) e unioni di tipo (vale a dire somma), quindi.

La corrispondenza sembra essere possibile solo sul tipo, ovvero è possibile chiedere se un valore con tipo di unione è uno dei tipi nell'unione e quindi il valore viene "riscritto" e si può accedere ai campi del tipo hai controllato

Problemi correlati