Действительно декларативный язык? - PullRequest
21 голосов
/ 07 июня 2010

Кто-нибудь знает действительно декларативный язык? Мне нужно поведение, похожее на то, что делает Excel, где я могу определять переменные и формулы, а также изменять результат формулы при изменении ввода (без повторного задания ответа)

Поведение, которое я ищу, лучше всего показано с помощью этого псевдокода:

X = 10     // define and assign two variables
Y = 20;

Z = X + Y  // declare a formula that uses these two variables

X = 50     // change one of the input variables

?Z         // asking for Z should now give 70 (50 + 20)

Я пробовал это на многих языках, таких как F #, Python, Matlab и т. Д., Но каждый раз, когда я пробую это, они получают 30 вместо 70. Это правильно с точки зрения императива, но я ищу более упрямое поведение, если вы понимаете, о чем я.

И это просто очень простой расчет. Когда все становится сложнее, он должен автоматически обрабатывать такие вещи, как рекурсия и запоминание.

Приведенный ниже код, очевидно, будет работать на C #, но это просто так много кода для работы, я ищу что-то более конкретное без всего этого "технического шума"

class BlaBla{
    public int X {get;set;}  // this used to be even worse before 3.0
    public int Y {get;set;}
    public int Z {get{return X + Y;}}
}

static void main(){
   BlaBla bla = new BlaBla();
   bla.X = 10;
   bla.Y = 20;
   // can't define anything here
   bla.X = 50; // bit pointless here but I'll do it anyway. 
   Console.Writeline(bla.Z);// 70, hurray!
}

Это просто похоже на большой код, фигурные скобки и точки с запятой, которые ничего не добавляют.

Есть ли язык / приложение (кроме Exel), которое делает это? Возможно, я не делаю это правильно в упомянутых языках или я полностью пропустил приложение, которое делает именно это.

Я создал прототип языка / приложения, который делает это (наряду с некоторыми другими вещами), и думаю о его создании. Я просто не могу поверить, что это еще не там. Не хочу тратить мое время.

Ответы [ 19 ]

1 голос
/ 07 июня 2010

Вы можете сделать это в Tcl, несколько. В tcl вы можете установить трассировку для переменной, чтобы при каждом обращении к ней можно было вызывать процедуру. Эта процедура может пересчитать значение на лету.

Ниже приведен рабочий пример, который делает более или менее то, что вы просите:

proc main {} {
    set x 10
    set y 20
    define z {$x + $y}

    puts "z (x=$x): $z"
    set x 50
    puts "z (x=$x): $z"
}


proc define {name formula} {
    global cache
    set cache($name) $formula
    uplevel trace add variable $name read compute
}

proc compute {name _ op} {
    global cache
    upvar $name var
    if {[info exists cache($name)]} {
        set expr $cache($name)
    } else {
        set expr $var
    }
    set var [uplevel expr $expr]
}

main
0 голосов
/ 10 июня 2010

Lua 5.1.4. Copyright (C) 1994-2008 Lua.org, PUC-Rio

х = 10
у = 20
z = function () return x + y; конец
х = 50
= z ()
70

0 голосов
/ 10 июня 2010

не уверен, насколько хорошо будет работать metapost ( 1 ) для вашего приложения, но он декларативный.

0 голосов
/ 08 июня 2010

Вы можете найти это видео (с веб-сайта Коммерческие пользователи функционального программирования ) интересным и полезным для просмотра. Если у вас довольно технофобные пользователи, это может быть хорошим подходом для вас.

0 голосов
/ 07 июня 2010

Вы можете имитировать это в Ruby:

x = 10
y = 20
z = lambda { x + y }
z.call    # => 30
z = 50
z.call    # => 70

Не вполне так же, как вы хотите, но довольно близко.

0 голосов
/ 07 июня 2010

Этот код F # должен помочь. Вы можете использовать ленивую оценку (объект System.Lazy), чтобы убедиться, что ваше выражение будет оценено, когда это действительно необходимо, а не раньше.

let mutable x = 10;
let y = 20;

let z = lazy (x + y);
x <- 30;

printf "%d" z.Value
0 голосов
/ 07 июня 2010

Это не то, что вы ищете, но языки описания аппаратных средств по определению являются "декларативными".

0 голосов
/ 07 июня 2010

В F # немного многословно:

let x = ref 10
let y = ref 20

let z () = !x + !y

z();;
y <- 40
z();;
0 голосов
/ 07 июня 2010

Groovy и магия замыканий.

def (x, y) = [ 10, 20 ]

def z = { x + y }

assert 30 == z()

x = 50

assert 70 == z()

def f = { n -> n + 1 }  // define another closure

def g = { x + f(x) }    // ref that closure in another

assert 101 == g()       // x=50, x + (x + 1)

f = { n -> n + 5 }     // redefine f()

assert 105 == g()      // x=50, x + (x + 5)

Можно также добавить автоматическое запоминание в функции, но это намного сложнее, чем просто одна или две строки. http://blog.dinkla.net/?p=10

...