Keine andere Programmiersprache. Teil 1: DomÀnenlogik



In letzter Zeit ist eine große Anzahl neuer Programmiersprachen auf den Markt gekommen: Go, Swift, Rust, Dart, Julia, Kotlin, Hack, Bosque - und dies ist nur eine von denen, die gehört werden.
Der Wert dessen, was diese Sprachen fĂŒr die Welt des Programmierens bringen, ist schwer zu ĂŒberschĂ€tzen, aber wie Y Combinator letztes Jahr feststellte, als er ĂŒber Entwicklungswerkzeuge sprach:
Frameworks werden besser, Sprachen sind etwas schlauer, aber im Grunde machen wir das Gleiche.
In diesem Artikel wird eine Sprache behandelt, die auf einem Ansatz basiert, der sich grundlegend von den in allen vorhandenen Sprachen verwendeten AnsĂ€tzen unterscheidet, einschließlich der oben aufgefĂŒhrten. Im Großen und Ganzen kann diese Sprache als Allzwecksprache betrachtet werden, obwohl einige ihrer Funktionen und die derzeitige Implementierung der darauf aufbauenden Plattform ihre Anwendung wahrscheinlich auf einen etwas engeren Bereich beschrĂ€nken - die Entwicklung von Informationssystemen.

Ich werde sofort eine Reservierung vornehmen. Es geht nicht um eine Idee, einen Prototyp oder sogar MVP, sondern um eine vollwertige produktionsbereite Sprache mit allen erforderlichen Infrastruktursprachen - von der Entwicklungsumgebung (mit einem Debugger) bis zur automatischen UnterstĂŒtzung mehrerer Versionen der Sprache (mit automatischen ZusammenfĂŒhrungs-Bugfixes zwischen diesen) , Versionshinweis usw.). DarĂŒber hinaus wurden mit dieser Sprache bereits mehrere Dutzend Projekte mit einer KomplexitĂ€t der ERP-Ebene implementiert, mit Hunderten von gleichzeitigen Benutzern, Terabyte-Datenbanken, „gestrigen Fristen“, begrenzten Budgets und Entwicklern ohne IT-Erfahrung. Und das alles zur gleichen Zeit. Nun, natĂŒrlich sollte angemerkt werden, dass jetzt nicht das Jahr 2000 ist und alle diese Projekte auf vorhandenen Systemen (die nicht vorhanden waren) implementiert wurden, was bedeutet, dass es zunĂ€chst notwendig war, das zu tun, was es war, ohne das GeschĂ€ft zu stoppen, und dann auch nach und nach tun, was es sein sollte. Im Allgemeinen können Sie auf diese Weise die ersten Elektroautos nicht an wohlhabende Hipster in Kalifornien, sondern an kostengĂŒnstige Taxidienste irgendwo in Omsk verkaufen.

Eine in dieser Sprache erstellte Plattform wird unter der LGPL v3-Lizenz veröffentlicht. Ehrlich gesagt wollte ich es nicht richtig in der Einleitung schreiben, da dies bei weitem nicht der wichtigste Vorteil ist, aber als ich mit Leuten sprach, die in einem der wichtigsten potenziellen MÀrkte - ERP-Plattformen - arbeiten, bemerkte ich eine Funktion: Alle diese Leute sagen dies ausnahmslos Selbst wenn Sie dasselbe tun, was bereits auf dem Markt ist, aber kostenlos, dann wird es bereits sehr cool sein. Also lass es hier.

Ein bisschen Theorie


Beginnen wir mit der Theorie, um den Unterschied in den grundlegenden AnsÀtzen hervorzuheben, die in dieser und anderen modernen Sprachen verwendet werden.

Ein kleiner Haftungsausschluss, weitere Überlegungen sind bis zu einem gewissen Grad ein Versuch, eine Eule auf den Globus zu ziehen, aber mit einer grundlegenden Theorie in der Programmierung sagen wir im Prinzip unverblĂŒmt, nicht wirklich, also mĂŒssen Sie verwenden, was ist.

Eine der allerersten und wichtigsten Aufgaben, die durch die Programmierung gelöst werden, ist das Problem der Berechnung der Werte von Funktionen. Aus rechentheoretischer Sicht gibt es zwei grundlegend unterschiedliche AnsÀtze zur Lösung dieses Problems.

Der erste derartige Ansatz sind verschiedene Maschinen (von denen die bekannteste eine Turing-Maschine ist) - ein Modell, das aus dem aktuellen Zustand (Speicher) und einer Maschine (Prozessor) besteht, die bei jedem Schritt diesen aktuellen Zustand auf die eine oder andere Weise Àndert. Dieser Ansatz wird auch als Architektur von Von Neumann bezeichnet. Er ist es, der allen modernen Computern und 99 Prozent der vorhandenen Sprachen zugrunde liegt.

Der zweite Ansatz basiert auf der Verwendung von Operatoren und wird von den sogenannten teilweise rekursiven Funktionen (im Folgenden: ChRF) verwendet. DarĂŒber hinaus besteht der Hauptunterschied zwischen diesem Ansatz nicht in der Verwendung von Operatoren als solchen (Operatoren verwenden beispielsweise auch die strukturelle Programmierung unter Verwendung des ersten Ansatzes), sondern in der Möglichkeit, ĂŒber alle Werte der Funktion zu iterieren (siehe den Operator zur Minimierung des Arguments) und in Abwesenheit von Zustand in Berechnungsprozess.

Wie die Turing-Maschine sind teilweise rekursive Funktionen Turing-vollstĂ€ndig, dh sie können verwendet werden, um jede mögliche Berechnung anzugeben. Hier stellen wir sofort klar, dass sowohl die Turing-Maschine als auch die CRF nur minimale Basen sind, und konzentrieren uns dann auf sie als AnsĂ€tze, dh auf ein Modell mit Prozessorspeicher und auf ein Modell mit Operatoren ohne Verwendung von Variablen und die Möglichkeit, ĂŒber alle Werte zu iterieren Funktionen jeweils.

Das CRF als Ansatz hat drei Hauptvorteile:

  • Es ist viel besser optimiert. Dies gilt sowohl direkt fĂŒr die Optimierung des Wertberechnungsprozesses als auch fĂŒr die Möglichkeit der ParallelitĂ€t einer solchen Berechnung. Im ersten Ansatz fĂŒhrt der Nacheffekt im Gegenteil zu einer sehr großen KomplexitĂ€t dieser Prozesse.
  • Es ist viel besser inkrementiert, dh fĂŒr eine konstruierte Funktion kann es viel effizienter sein, zu bestimmen, wie sich ihre Werte Ă€ndern, wenn sich die Werte der Funktionen Ă€ndern, die diese erstellte Funktion verwendet. Genau genommen ist dieser Vorteil ein Sonderfall des ersten, aber genau dies bietet eine Vielzahl von Möglichkeiten, die im ersten Ansatz grundsĂ€tzlich nicht möglich sind, weshalb er als separater Punkt hervorgehoben wird.
  • Es ist viel einfacher zu verstehen. Das heißt, grob gesagt ist die Beschreibung der Funktion der Berechnung der Summe eines Indikators im Kontext von zwei anderen Indikatoren viel einfacher zu verstehen, als wenn dieselbe im Hinblick auf den ersten Ansatz beschrieben wird. Bei algorithmisch komplexen Problemen ist die Situation diametral entgegengesetzt, es ist jedoch anzumerken, dass algorithmisch komplexe Probleme in der ĂŒberwiegenden Mehrheit der Bereiche gut sind, wenn 5%. Um es kurz zusammenzufassen: CRF ist im Allgemeinen Mathematik, und Turing-Maschinen sind Informatik. Dementsprechend wird Mathematik fast im Kindergarten studiert, und Informatik ist optional und von der High School. So lala Vergleich natĂŒrlich, gibt aber immer noch eine Art Metrik in dieser Angelegenheit.

Turingmaschinen haben mindestens zwei Vorteile:

  • Bereits erwĂ€hnte beste Anwendbarkeit bei algorithmisch komplexen Problemen
  • Alle modernen Computer bauen auf diesem Ansatz auf.

Außerdem geht es in diesem Vergleich nur um Datenberechnungsaufgaben. Bei Problemen beim Ändern von Daten ohne Turing-Maschinen ist dies immer noch nicht möglich.

Nach dem Lesen an dieser Stelle wird jeder aufmerksame Leser eine vernĂŒnftige Frage stellen: „Wenn der CRF-Ansatz so gut ist, warum wird er in keiner gemeinsamen modernen Sprache verwendet?“ TatsĂ€chlich ist dies also nicht der Fall, sondern wird in der Sprache verwendet, die in der ĂŒberwiegenden Mehrheit der vorhandenen Informationssysteme verwendet wird. Wie Sie vielleicht erraten haben, ist diese Sprache SQL. Hier wird natĂŒrlich derselbe aufmerksame Leser vernĂŒnftigerweise einwenden, dass SQL die Sprache der relationalen Algebra ist (dh mit Tabellen und nicht mit Funktionen arbeitet), und es wird richtig sein. Formal. TatsĂ€chlich können wir uns daran erinnern, dass die Tabellen im DBMS normalerweise in der dritten Normalform vorliegen, dh SchlĂŒsselspalten haben, was bedeutet, dass jede verbleibende Spalte dieser Tabelle als Funktion ihrer SchlĂŒsselspalten betrachtet werden kann. Ehrlich gesagt nicht offensichtlich. Und warum SQL nicht von einer relationalen Algebra-Sprache zu einer vollwertigen Programmiersprache gewachsen ist (dh mit Funktionen arbeitet), ist eine große Frage. Meiner Meinung nach gibt es dafĂŒr viele GrĂŒnde, von denen der wichtigste darin besteht, dass „ein Russe (in der Tat jeder) nicht auf nĂŒchternen Magen arbeiten kann, aber nicht an einem gut ernĂ€hrten arbeiten möchte“, in dem Sinne, dass, wie die Praxis zeigt, die dafĂŒr notwendige Arbeit Es ist wirklich titanisch und birgt zu viele Risiken fĂŒr kleine Unternehmen und fĂŒr große Unternehmen - erstens ist alles in Ordnung, und zweitens ist es unmöglich, diese Arbeit mit Geld zu erzwingen - QualitĂ€t ist hier wichtig, nicht QuantitĂ€t. Das anschaulichste Beispiel dafĂŒr, was passiert, wenn Menschen versuchen , ein Problem eher nach QuantitĂ€t als nach QualitĂ€t zu lösen, ist Oracle, das es sogar geschafft hat, selbst die grundlegendste Anwendung von InkrementalitĂ€t zu implementieren - aktualisierte materialisierte Darstellungen, so dass dieser Mechanismus eine Reihe von EinschrĂ€nkungen auf mehreren Seiten aufweist (Gerechtigkeit). Microsoft ist noch schlimmer . Dies ist jedoch eine separate Geschichte, vielleicht wird es einen separaten Artikel darĂŒber geben.

Gleichzeitig ist SQL nicht schlecht. Nein. Auf seiner Abstraktionsebene fĂŒhrt es seine Funktionen perfekt aus, und die aktuelle Implementierung der Plattform nutzt sie etwas weniger als vollstĂ€ndig (auf jeden Fall viel mehr als alle anderen Plattformen). Eine andere Sache ist, dass SQL unmittelbar nach seiner Geburt tatsĂ€chlich in der Entwicklung stehen blieb und nicht das wurde, was es werden konnte, nĂ€mlich die Sprache, die jetzt diskutiert wird.

Aber genug Theorie, es ist Zeit, direkt zur Sprache zu gehen.

Also treffen wir uns:


Insbesondere wird dieser Artikel der erste von drei Artikeln sein (da selbst fĂŒr zwei Artikel noch zu viel Material vorhanden ist), und es wird nur ĂŒber das logische Modell gesprochen, dh nur darĂŒber, was in direktem Zusammenhang mit der FunktionalitĂ€t des Systems steht und nicht mit Prozessen Entwicklung und Implementierung (Leistungsoptimierung). DarĂŒber hinaus werden wir nur ĂŒber einen der beiden Teile des logischen Modells sprechen - die Logik des Themenbereichs. Diese Logik bestimmt, welche Informationen das System speichert und was Sie mit diesen Informationen tun können (bei der Entwicklung von GeschĂ€ftsanwendungen wird sie hĂ€ufig auch als GeschĂ€ftslogik bezeichnet).

Grafisch können alle Konzepte der DomÀnenlogik in lsFusion durch das folgende Bild dargestellt werden:


Die Pfeile in diesem Bild geben die Verwendungsrichtungen der Konzepte voneinander an, daher bilden die Konzepte eine Art Stapel, und dementsprechend werde ich in der Reihenfolge dieses Stapels darĂŒber sprechen.


Die Eigenschaften


Eine Eigenschaft ist eine Abstraktion, die ein oder mehrere Objekte als Parameter verwendet und als Ergebnis ein Objekt zurĂŒckgibt. Die Eigenschaft hat keine Nachwirkung und ist in der Tat eine reine Funktion. Im Gegensatz zu letzterer kann sie jedoch Werte nicht nur berechnen, sondern auch speichern. TatsĂ€chlich ist der Name "Eigenschaft" selbst aus anderen modernen Programmiersprachen entlehnt, wo er fĂŒr ungefĂ€hr die gleichen Zwecke verwendet wird, aber er ist an die Kapselung gebunden und wird daher nur fĂŒr Funktionen mit einem Parameter unterstĂŒtzt. Nun, die Tatsache, dass genau dieses Wort „Eigenschaft“ kĂŒrzer als „reine Funktion“ ist und keine unnötigen Assoziationen aufweist, spricht fĂŒr die Verwendung dieses bestimmten Begriffs.

Eigenschaften werden rekursiv mithilfe eines vordefinierten Satzes von Operatoren festgelegt. Es gibt viele dieser Operatoren, daher betrachten wir nur die Hauptoperatoren (diese Operatoren decken 95% aller durchschnittlich statischen Projekte ab).

PrimÀreigenschaft (DATA)


Die primĂ€re Eigenschaft ist eine Eigenschaft, deren Wert in der Datenbank gespeichert ist und die aufgrund der entsprechenden Aktion (etwas spĂ€ter) geĂ€ndert werden kann. StandardmĂ€ĂŸig entspricht der Wert jeder solchen Eigenschaft fĂŒr einen beliebigen Parametersatz einem speziellen NULL-Wert.
quantity = DATA INTEGER (Item);
isDayOff = DATA BOOLEAN (Country, DATE);
, ( ), .

. :

class X { 	
    Y y; 	
    Map<Y, Z> f; 	
    Map<Y, Map<M, Z>> m; 	
    List<Y> n;
    LinkedHashSet<Y> l; //   
    static Set<Y> s;
}

:
y = DATA Y (X);
f = DATA Z (X, Y);
m = DATA Z (X, Y, M);
n = DATA Y (X,INTEGER);
l = DATA INTEGER (X,Y);
s = DATA BOOLEAN (Y);

(JOIN), , (+,-,/,*), (AND, OR), (+, CONCAT), (>,<,=), (CASE, IF), (IS)

f(a) = IF g(h(a)) > 5 AND a IS X THEN â€˜AB’ + â€˜CD’ ELSE x(5);
- , . , , , :

  • , . , ( NULL). , lsFusion – , , , – TRUE ( FALSE NULL), 3-state’.
  • NULL: (+), (-), CONCAT . :
    • : NULL 0, – , 0 NULL ( 5 (+) NULL = 5, 5 (-) 5 = NULL, 5 + NULL = NULL 5 — 5 = 0).
    • : NULL ( CONCAT ‘ ‘, ‘John’,’Smith’ = ‘John Smith’, CONCAT ‘ ‘, ‘John’, NULL = ‘John’, ‘John’ + ‘ ‘ + NULL = NULL).
  • (IF) ( ) : f(a) IF g(a), f(a) g(a) NULL, NULL – .

(GROUP)


– . (, ) .

:

  • :
    sum(Invoice i) = GROUP SUM sum(InvoiceDetail id) IF invoice(id) = i;
    currentBalance(Sku sk) = GROUP SUM currentBalance(sk, Stock st);
    , ( i sk). , , - :
    x() = (GROUP SUM f(a)) + 5;
  • SQL-:
    sum = GROUP SUM sum(InvoiceDetail id) BY invoice(id);
    currentBalance = GROUP SUM currentBalance(Sku sk, Stock st) BY sk;
    ( , , )

, ( ), – ( ). , , , ( , , SQL – ). , ( BY), - :
// BY     ,   s
sum(DATE from, Stock s, DATE to) = GROUP sum(Invoice i) IF date(i) >= from AND date(i) <=to BY stock(i); 
, , , , , .

:

  • /,

  • .

/ (PARTITION 
 ORDER)


( , ) , . , ( , ). / .
place(Team t) = PARTITION SUM 1 ORDER DESC points(t) BY conference(t);
, , , , , , .

SQL ( , ) (OVER PARTITION BY
 ORDER BY).

(RECURSION)


– , . , , .

. , ( ):

  • (result) ( ) :
    • result(0, o1, o2, ..., oN) = initial(o1, ..., oN), initial –
    • result(i+1, o1, o2, ..., oN) = step(o1, ..., oN, $o1, $o2, ..., $oN) IF result(i, $o1, $o2, ..., $oN), step – .
  • , ( o1, o2, 
, oN). , .

, , , , :
//   integer  from  to (       System)
iterate(i, from, to) = RECURSION i=from STEP i=$i+1 AND i<=to CYCLES IMPOSSIBLE;
 
//      a  b   ( ,  ,  )
edge = DATA BOOLEAN (Node, Node);
pathes '- ' (a, b) = RECURSION 1 IF b=a STEP 1 IF edge(b, $b);
 
// ,     child  parent,  null,     (         child')
parent  = DATA Group (Group);
level '' (Group child, Group parent) = RECURSION 1 AND child IS Group AND parent = child STEP 1 IF parent = parent($parent);
 
//  ,        to, (   NULL)
fib(i, to) = RECURSION 1 IF (i=0 OR i=1STEP 1 IF (i=$i+1 OR i=$i+2AND i<to CYCLES IMPOSSIBLE;
, / , , , .

, , , , , lsFusion – .

SQL CTE, , , . , Postgres GROUP BY , , , , , , . , , WHILE’ .

. , , .


– , , , , ( , , ). , , “”, , -, , , -, , “”.

, – lsFusion. , – . , – ( , , , ). , – . .

, . / , , , , , . 3 97, lsFusion – 60 40.

, , . , -, ( , ), .

, :

(FOR), (WHILE)


, lsFusion , , NULL ( ).
FOR selected(Team team) DO
    MESSAGE 'Team ' + name(team) + ' was selected';
, :
showAllDetails(Invoice i) {
    FOR invoice(InvoiceDetail id) = i ORDER index(id) DO
        MESSAGE 'Sku : ' + nameSku(id) + ', ' + quantity(id);
}
, , (IF).

(WHILE) , :

  • , NULL ( )


(EXEC), ({
}), (CASE, IF), (BREAK), (RETURN)

f(a) {
    FOR t=x(b,a) DO {
        do(b);
        IF t>5 THEN
            BREAK;
    }
    MESSAGE 'Succeeded';
}
- . , , .

(CHANGE)


. , , , , NULL. :
//       
setDiscount(Customer c)  {
    discount(c, Item i) <- 15 WHERE selected(i);
}
, :
setDiscount(Customer c)  {
    FOR selected(Item i) DO
        discount(c, i) <- 15;
}
, , , ( , , , , selected discount – ), . , , .

(NEW)


( , , , , ). , , .

:
newSku ()  {
    LOCAL addedSkus = Sku (INTEGER);
    NEW Sku WHERE iterate(i, 13TO addedSkus(i);
    FOR Sku s = addedSkus(i) DO {
        id(s) <- 425;
        name(s) <- 'New Sku : ' + i;
    }
}
, , — NEW (FOR), ( ):
FOR iterate(i, 13NEW s=Sku DO  {
    id(s) <- i;
    name(s) <- 'New Sku : ' + i;
}
, FOR :
NEW s=Sku DO {
    id(s) <- 425;
    name(s) <- 'New Sku';
}
– , , , .

(DELETE)


– :
DELETE Sku s WHERE name(s) = 'MySku';
, «» .

, , .


, , . , , . .

, . , — / .

, , . , ( ), .

, , . , :
LOCAL f = INTEGER (INTEGERINTEGER);

f(1,3) <- 6;
f(2,2) <- 4;
f(f(1,3),4) <- 5;
f(a,a) <- NULL//      1-  2-  (  2,2)

MESSAGE GROUP CONCAT a + ',' + b + '->' + f(a, b),' ; '//  1,3->6 ; 6,4->5
: (APPLY) (CANCEL). , , , . , , , . – , , , , . — .

(NEWSESSION, NESTEDSESSION)


(, , http- ..). , , . , , , «», «» ( , ). NEWSESSION, ( ). :
run() {
    f(1) <- 2;
    APPLY;
    f(1) <- 1;
    NEWSESSION {
        MESSAGE f(1); //  2,       
        f(2) <- 5;
        APPLY;          
    }
    MESSAGE f(1); //  1,     1  ,   
}
, , , . , :
run(Store s) {
    NEWSESSION
        MESSAGE 'I see that param, its name is: ' + name(s);
}
, , ( ). NESTED, , , , . , ( , NESTED). :
g = DATA LOCAL NESTED INTEGER ();
run() {
    f(1) <- 1; g() <- 5;
    NEWSESSION NESTED (f) {
        MESSAGE f(1) + ' ' + g(); //  1 5
        f(1) <- 5; g() <- 7;
    }
    MESSAGE f(1) + ' ' + g(); //  5 7
}
. :

  • , , , < —
  • , , : < —
  • , : < — .

, (, ), , . , , - , , , , , :


  • ,

(APPLY), (CANCEL)


– , . , . , :

  • . , , , NESTED ( ).
  • , . , - , , , . , (update conflict), , , . , :

// -------------------------- Object locks ---------------------------- //
 
locked = DATA User (Object);
lockResult = DATA LOCAL NESTED BOOLEAN ();
 
lock(Object object)  {
    NEWSESSION { 
        lockResult() < - NULL;
        APPLY SERIALIZABLE {
            IF locked(object) THEN {
                CANCEL;
            } ELSE {
                locked(object) <- currentUser();
                lockResult() <- TRUE;
            }
        }
    }
}
 
unlock(Object object)  {
    NEWSESSION
        APPLY locked(object) <- NULL;
}
PS: Authentication, , , ( ) ( ). , , lsFusion , (, ).

– , , , , ( ).

(PREV, CHANGED, SET, DROPPED)


: (PREV), (CHANGED), NULL NULL (SET) .. ( ), , , :
f = DATA INTEGER (INTEGER);
run() {
    f(1) <- 2;
    APPLY;
 
    f(1) <- 5;
    f(2) <- 3;
    MESSAGE GROUP SUM 1 IF CHANGED(f(a)); // ,    f     ,  2
    MESSAGE '. : ' + f(1) + ', . : ' + PREV(f(1)); //  . : 5, . : 2
}
. , , , , .


“ ?”, “ ?”. , , .

, , . , . .

:

  • – .
  • – , / .

, , :

  • – .
  • – .

, , , .

:

  • , , , .
  • , .

:

  • , « ». , , , ( , , 5-10 , ).
  • , ( ), , , , .

:

  • , , .

:

  • , , ( ), , .

( , ), .
ON { //   ,       APPLY
    MESSAGE 'Something changed';
}
, , , , ‘Something changed’ (!) ( , ). , , - , (CHANGED, SET, DROPPED ..). , - , -, -. – :
//  email,          
WHEN SET(balance(Sku s, Stock st) < 0DO
      EMAIL SUBJECT '     ' + name(s) + '   ' + name(st);

WHEN LOCAL CHANGED(customer(Order o)) AND name(customer(o)) == 'Best customer' DO
    discount(OrderDetail d) <- 50 WHERE order(d) = o;

, – , . , :
ON {
    FOR SET(balance(Sku s, Stock st) < 0DO
        EMAIL SUBJECT '     ' + name(s) + '   ' + name(st);
}
, , / , , .

SQL ( ) . , , , ( ) , .

, :

  • – , ( )
  • – , . , , «» .


, , . , , NULL:
//    0
CONSTRAINT balance(Sku s, Stock st) < 0 
    MESSAGE '    ';

// ""  
CONSTRAINT DROPCHANGED(barcode(Sku s)) AND name(currentUser()) != 'admin' 
    MESSAGE ' -       ';

//      ,   
CONSTRAINT sku(OrderDetail d) AND NOT in(sku(d), customer(order(d)))
    MESSAGE '        ';
, – , NULL (SET) , – NULL . – , , , / , .

, – ( ), , , ( ), , .


. , , , – . , :
f = DATA A (INTEGER);
, f NULL , A. :
f = Object (INTEGER);
CONSTRAINT f(i) AND NOT f(i) IS A MESSAGE ' '// f(i) => f(i) IS A
, , – . ( , , «»), , , , : - , .

, lsFusion . , lsFusion . , . lsFusion , , - :
CLASS A {
    f = DATA LONG (INTEGER); //  f = DATA LONG (A, INTEGER)
}
lsFusion , :
CLASS Animal;
CLASS Transport;
CLASS Car : Transport;
CLASS Horse : Transport, Animal;
, – .


lsFusion – . , , :
speed = ABSTRACT LONG (Transport);
/ , :
CLASS Breed;
speed = DATA LONG (Breed)
breed = DATA Breed (Animal);

speed(Horse h) += speed(breed(h)); //       
( ):
CLASS Thing;
CLASS Ship : Thing;
CLASS Asteroid : Thing;

collide ABSTRACT (Thing, Thing);
collide(Ship s1, Ship s2) +{
    MESSAGE 'Ship : ' + name(s1) + ', Ship : ' + name(s2);
}
collide(Ship s1, Asteroid a2) +{
    MESSAGE 'Ship : ' + name(s1) + ', Asteroid : ' + name(a2);
}
collide(Asteroid a1, Ship s2) +{
    MESSAGE 'Asteroid : ' + name(a1) + ', Ship : ' + name(s2);
}
collide(Asteroid a1, Asteroid a2) +{
    MESSAGE 'Asteroid : ' + name(a1) + ', Asteroid : ' + name(a2);
}
, , ( ), . ABSTRACT :
speed(Transport t) = CASE 
    WHEN t IS Horse THEN speed(breed(t))
    //  
END
, .

, , :
speed(Horse h) = speed(breed(h));
, , ( ). , , .


, , . () : , , . , , , , , . NULL , , :
f = DATA LONG (LONG);
g = DATA LONG (A);
h(a) = OVERRIDE f(a), g(a); //   


( ) – , . , , , :
CLASS Direction '' {
    left '',
    right '',
    forward ''
}

result(dir) = CASE
    WHEN dir = Direction.left THEN ' '
    WHEN dir = Direction.right THEN ' '
    WHEN dir = Direction.forward THEN ' '
END
, .

enum’, , .


( lsFusion, ) :

  • ( ).
  • ( ).
  • .

.

() , NULL . , , , , , .

:
//   A    B
b(A a) = AGGR B WHERE a IS A; 
//     a     B    A,   b(a(b)) = b

createC = DATA BOOLEAN (A, B)
//    A  B    createC    C
//     ,       ,      
c = AGGR C WHERE createC(A a, B b); 
//     a  b     C      B 
, , ( ):
CLASS Shipment '';
date = ABSTRACT DATE (Shipment);
CLASS Invoice '';
createShipment ' ' = DATA BOOLEAN (Invoice);
date ' ' = DATA DATE (Invoice);
CLASS ShipmentInvoice '  ' : Shipment;
//    ,       
shipment(Invoice invoice) = AGGR ShipmentInvoce WHERE createShipment(invoice);
date(ShipmentInvoice si) += sum(date(invoice(si)),1); //   =   + 1
, (, ), ( ) , . , ERP 1100 . , , , . , ( 50 ), , 1100 300 .

, , , , . , , – , – , , , « - », , , .


, lsFusion . , , , , , , , , , ( , , ). , lsFusion ( ACID), , SQL-, . , DSL lsFusion , , – – . , SQL , , lsFusion . , , – , github ( , ), (IDE, , VCS, ), slack telegram- , (linux maven, - ), , , , , lsFusion , SQL, ABAP 1 – .

, , lsFusion, , ( ), : ERP-, SQL- , ORM-, RAD-, . , , .

, :

  • SQL- – - – , , .
  • ERP- – - – , , ..
  • ORM- – - (, ), .
  • RAD – - , , , IT-.
  • – , RAD, , - , , Excel (, , , – ).

, lsFusion ERP, RAD SQL , lsFusion ( ). , SQL, , , , , , Fortran C ( , ). ORM- , – . , , - .

SME ( , ), ( ). , 1 , .

, , , , , ( 12 ), .

UPD: .

Source: https://habr.com/ru/post/de458376/


All Articles