没有其他编程语言。 第1部分:领域逻辑



最近,市场上出现了许多新的编程语言:Go,Swift,Rust,Dart,Julia,Kotlin,Hack,Bosque-这只是其中一种。
这些语言带给编程世界的价值很难被高估,但是正如Y Combinator去年在谈到开发工具时指出的那样
框架变得越来越好,语言变得更聪明了,但是基本上我们都这样做。
本文将讨论一种基于与所有现有语言(包括上面列出的语言)中使用的方法完全不同的方法构建的语言。 总的来说,该语言可以被认为是一种通用语言,尽管它的某些功能和基于该语言的平台的当前实现可能会将其应用限制在一个略为狭窄的领域-信息系统的开发。

我将立即进行预定,这与想法,原型甚至MVP无关,而是与功能完备的生产就绪语言以及所有必需的基础结构语言有关的信息-从开发环境(带有调试器)到自动支持多种语言版本(它们之间具有自动合并错误修正) ,发行说明等)。 此外,使用这种语言,已经实施了数十个具有ERP级别复杂性的项目,其中有数百个同时用户,TB级数据库,“昨天的截止日期”,有限的预算以及没有IT经验的开发人员。 并且所有这些都在同一时间。 好吧,当然,应该指出的是,现在不是2000年,所有这些项目都是在现有系统(尚不存在)的基础上实施的,这意味着,首先有必要逐步“照原样”开展业务,而不必停止业务,然后,也逐步地,应该做的。 总的来说,这是如何向加利福尼亚的富裕人群而不是鄂木斯克某处的廉价出租车服务出售首批电动汽车的方法。

在LGPL v3许可下发布了以此语言构建的平台。 老实说,我不想在引言中写得很对,因为这远没有它的最重要的优势,但是,与在其主要潜在市场之一-ERP平台上工作的人们交谈时,我注意到了一个功能:所有这些人无一例外地表示:即使您这样做已经是市场上的免费服务,但它已经非常酷了。 所以把它留在这里。

一点理论


让我们从理论开始,以突出此语言和其他现代语言所使用的基本方法的差异。

一个小的免责声明,在某种程度上进一步的推理是试图在地球上拉猫头鹰,但是原则上说,在编程的基本理论上,直率地说,不是真的,所以您必须使用现有的东西。

通过编程解决的首要任务和主要任务之一是计算函数值的问题。 从计算理论的角度来看,有两种根本不同的方法来解决此问题。

第一种这样的方法是各种机器(其中最著名的是图灵机)-由当前状态(内存)和机器(处理器)组成的模型,它们在每一步都以一种或另一种方式更改此当前状态。 这种方法也称为冯·诺依曼(Von Neumann)的体系结构,正是他是所有现代计算机和99%的现有语言的基础。

第二种方法基于运算符的使用;它被所谓的部分递归函数 (以下称为ChRF)使用。 而且,这种方法之间最重要的区别不在于使用运算符本身(例如,运算符也在使用第一种方法的结构化编程中),而是可能遍历该函数的所有值(请参见将参数最小化的运算符)以及在没有状态的情况下。计算过程。

像图灵机一样,部分递归函数也是图灵完整的,也就是说,它们可以用于指定任何可能的计算。 在这里,我们立即阐明,图灵机和CRF都是最小的基础,然后我们将它们作为方法来关注,即,关注具有处理器内存的模型以及关注于不使用变量的运算符的模型以及对所有值进行迭代的可能性功能。

CRF作为一种方法具有三个主要优点:

  • 优化效果更好。 这不仅直接适用于计算值过程的优化,而且适用于这种计算的并行性。 相反,在第一种方法中,后效应给这些过程带来了非常大的复杂性。
  • 它的增量要好得多,也就是说,对于已构建的函数,当此已构建函数使用的函数的值发生更改时,确定其值将如何更改会更加有效。 严格来说,这种优势是第一种方法的特殊情况,但恰恰是这种优势提供了很多可能性,而这在第一种方法中基本上是不可能的,因此将其突出显示为一个单独的项目。
  • 这很容易理解。 也就是说,粗略地说,与在第一种方法中描述的相同的情况下,对在另外两个指标的上下文中计算一个指标之和的功能的描述要容易理解得多。 但是,在算法复杂的问题中,情况截然相反,但值得注意的是,如果百分比为5%,则在绝大多数区域中算法复杂的问题都很好。 总的来说,CRF是数学,图灵机是计算机科学。 因此,数学几乎是在幼儿园学习的,计算机科学是可选的,并且是从高中毕业的。 当然,一般的比较,但是在这个问题上仍然给出了某种度量。

图灵机至少具有两个优点:

  • 已经提到算法复杂问题的最佳适用性
  • 所有现代计算机都基于这种方法。

另外,在此比较中,我们仅讨论数据计算任务;在没有图灵机的情况下更改数据的问题,您仍然无法做到。

读到这个地方后,任何专心的读者都会问一个合理的问题:“如果CRF方法如此好,为什么不以任何常见的现代语言使用它?” 因此,实际上并非如此,而且,它以绝大多数现有信息系统中使用的语言使用。 您可能会猜到,这种语言是SQL。 当然,在这里,同样的专心读者会合理地反对SQL是关系代数的语言(也就是说,使用表而不是函数),这是正确的。 正式地。 实际上,我们可以回想起DBMS中的表通常采用第三范式,即它们具有键列,这意味着该表的任何其余列都可以视为其键列的函数。 坦白说,这并不明显。 为什么SQL没有从关系代数语言发展为成熟的编程语言(即使用函数),这是一个很大的问题。 在我看来,这有许多原因,其中最重要的是“俄罗斯人(实际上是任何人)不能空腹工作,但又不想在饮食饱满的情况下工作”,正如实践所表明的那样,它确实是泰坦尼克号,对小公司和大公司都承担着太多的风险,首先,一切都很好,其次,不可能用金钱来迫使这项工作—质量在这里很重要,而不是数量。 实际上,当人们尝试通过数量而不是质量解决问题时,发生情况的最生动的例证是Oracle,Oracle甚至设法实现了最基本的增量应用程序-更新的物化表示形式,因此该机制具有若干页的限制 (正义)出于这个原因,微软仍然更糟 )。 但是,这是一个单独的故事,也许会有单独的文章。

同时,并不是说SQL是不好的。 不行 在其抽象级别上,它可以完美地执行其功能,并且该平台的当前实现使用它的功能要比完全使用的功能少(无论如何,比所有其他平台使用的功能要多得多)。 另一件事是,SQL刚诞生后实际上就停止了开发,并没有变成它可能变成的样子,即现在将要讨论的语言。

但是有足够的理论,是时候直接学习语言了。

因此,我们见面


具体来说,本文将是三篇的第一部分(因为即使有两篇文章,仍然有太多的材料),并且只讨论逻辑模型-也就是说,仅讨论与系统功能直接相关且与流程无关的内容开发和实施(性能优化)。 此外,我们将仅讨论逻辑模型的两个部分之一-主题区域的逻辑。 此逻辑确定系统存储哪些信息以及您可以使用此信息做什么(在开发业务应用程序时,通常也称为业务逻辑)。

以图形方式,lsFusion中域逻辑的所有概念可以由下图表示:


此图中的箭头指示彼此概念的使用方向,因此,这些概念形成一种堆栈,因此,我将按照这些堆栈的顺序来讨论它们。


属性


属性是一种抽象,它将一个或多个对象作为参数,并返回一些对象。 该属性没有后效应,实际上是一个纯函数,但是与后者不同,它不仅可以计算值,而且可以存储它们。 实际上,“属性”这个名称本身是从其他现代编程语言中借用的,在此语言中,“属性”的用途大致相同,但它被钉在封装中,因此仅支持具有一个参数的函数。 好吧,事实上这个“财产”一词比“纯功能”短,而且没有不必要的联系,这有利于使用这个特定术语。

使用一组预定义的运算符来递归设置属性。 这些运算符很多,因此,我们仅考虑主要运算符(这些运算符覆盖所有平均静态项目的95%)。

主要属性(DATA)


主属性是一个属性,其值存储在数据库中,并且可以通过相应操作(稍后进行更改)进行更改。 默认情况下,任何一组参数的每个此类属性的值都等于一个特殊的NULL值。
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/zh-CN458376/


All Articles