Кто-либо знает о действительно декларативном языке? Поведение, которое я ищу, отчасти, что делает 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. Который корректен с обязательной точки зрения, но я ищу более декларативное поведение, если Вы понимаете, о чем я.
И это - просто очень простое вычисление. Когда вещи становятся более трудными, это должно обработать материал как рекурсия и memoization автоволшебно.
Код ниже, очевидно, работал бы в 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), который делает это? Возможно, я - не делать правильно его на упомянутых языках, или я полностью пропустил приложение, которое делает просто это.
Я моделировал язык / приложение, которое делает это (наряду с некоторым другим материалом) и думает о productizing он. Я просто не могу полагать, что это еще не там. Не хочу тратить впустую свое время.
Любая система программирования с ограничениями сделает это за вас. Примерами систем CP, имеющих связанный язык, являются ECLiPSe, SICSTUS Prolog / CP пакет, Comet, MiniZinc, ....
Это не то, что вы ищете, но языки описания оборудования по определению являются «декларативными».
Вот пример Дэниела на Python, поскольку я заметил, что вы сказали, что пробовали его на Python.
x = 10
y = 10
z = lambda: x + y
# Output: 20
print z()
x = 20
# Output: 30
print z()
В системе Mathematica вы можете сделать следующее:
x = 10; (* # assign 30 to the variable x *)
y = 20; (* # assign 20 to the variable y *)
z := x + y; (* # assign the expression x+y to the variable z *)
Print[z];
(* # prints 30 *)
x = 50;
Print[z];
(* # prints 70 *)
Оператор : =
(SetDelayed) отличается от =
(Set). Первый связывает неоцененное выражение с переменной, последний связывает оцененное выражение .
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
Две вещи, на которые вы можете обратить внимание, - это библиотека cells lisp и язык динамического моделирования Modelica , оба из которых имеют возможности отношений / уравнений.
Вы видели Resolver One? Это как Excel с настоящим языком программирования за спиной.
Похоже, вы просто хотите, чтобы Z сохраняла функцию вместо значения. В C #:
var X = 10; // define and assign two variables
var Y = 20;
Func<int> Z = () => X + Y; // declare a formula that uses these two variables
Console.WriteLine(Z());
X = 50; // change one of the input variables
Console.WriteLine(Z());
Таким образом, эквивалентом синтаксиса префикса ?
является суффикс ()
, но в остальном он идентичен. Лямбда - это «формула» в вашей терминологии.
За кулисами компилятор C # строит почти в точности то, что вы представили в концептуальном примере C #: он превращает X
в поле в классе, созданном компилятором, и выделяет экземпляр этого класса, когда кодовый блок введен. Поздравляем, вы заново открыли лямбды! :)
В F #, немного многословно:
let x = ref 10
let y = ref 20
let z () = !x + !y
z();;
y <- 40
z();;
react - это библиотека OCaml frp. В отличие от наивных эмуляций с замыканиями, он будет пересчитывать значения только при необходимости
Objective Caml version 3.11.2
# #use "topfind";;
# #require "react";;
# open React;;
# let (x,setx) = S.create 10;;
val x : int React.signal = <abstr>
val setx : int -> unit = <fun>
# let (y,sety) = S.create 20;;
val y : int React.signal = <abstr>
val sety : int -> unit = <fun>
# let z = S.Int.(+) x y;;
val z : int React.signal = <abstr>
# S.value z;;
- : int = 30
# setx 50;;
- : unit = ()
# S.value z;;
- : int = 70
Вы можете имитировать это в Ruby:
x = 10
y = 20
z = lambda { x + y }
z.call # => 30
z = 50
z.call # => 70
Не совсем то, что вы хотите, но довольно близко.
JavaFX сделает это за вас, если вы используете bind
вместо =
для Z
Этот код на F# должен помочь. Вы можете использовать ленивую оценку (объект System.Lazy), чтобы гарантировать, что ваше выражение будет оценено, когда это действительно необходимо, а не раньше.
let mutable x = 10;
let y = 20;
let z = lazy (x + y);
x <- 30;
printf "%d" z.Value
Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
x = 10
y = 20
z = function () return x + y; конец
х = 50
= z ()
70
Вы можете найти это видео (с сайта Commercial Users of Functional Programming) интересным и достойным просмотра. Если у вас есть пользователи, страдающие технофобией, это может быть хорошим подходом для вас.
не уверен, насколько хорошо метапост (1) подойдет для вашего приложения, но он декларативен.
Вы можете сделать это в 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
Желание иметь два определения X является по своей сути императивным. В истинно декларативном языке у вас есть одно определение переменной в одной области видимости. Поведение, которого вы хотите от Excel, соответствует редактированию программы.