Ответ 1
Любая система Constraint Programming сделает это за вас. Примеры систем CP, которые имеют связанный язык, ECLiPSe, пакет SICSTUS Prolog/CP, комета, MiniZinc,...
Кто-нибудь знает действительно декларативный язык? Поведение, которое я ищу, - это то, что делает 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. Это верно с императивной точки зрения, но я ища более децилераторное поведение, если вы знаете, что я имею в виду.
И это просто очень простой расчет. Когда все становится сложнее, он должен автоматически обрабатывать такие вещи, как рекурсия и мемонирование.
Нижеприведенный код, очевидно, будет работать на С#, но это всего лишь код для задания, я ищу что-то немного больше, не говоря уже о том, что "технический шум"
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), которое это делает? Возможно, я не делаю это правильно в упомянутых langauges, или я полностью пропустил приложение, которое делает именно это.
Я прототипировал язык/приложение, которое делает это (наряду с некоторыми другими вещами), и я думаю о его выпуске. Я просто не могу поверить, что это еще не все. Не хочу тратить свое время.
Любая система Constraint Programming сделает это за вас. Примеры систем CP, которые имеют связанный язык, ECLiPSe, пакет SICSTUS Prolog/CP, комета, MiniZinc,...
Похоже, вы просто хотите, чтобы Z сохранила функцию вместо значения. В С#:
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());
Итак, эквивалент синтаксиса ?
-rerefix - это ()
-suffix, но в остальном он идентичен. Лямбда - это "формула" в вашей терминологии.
За кулисами компилятор С# строит почти то же, что вы представили в своем концептуальном примере С#: он превращает X
в поле в классе, генерируемом компилятором, и выделяет экземпляр этого класса при вводе кода кода, Итак, поздравляю, вы вновь обнаружили лямбда!:)
В 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). Первый связывает неоцененное выражение с переменной, последнее связывает оцениваемое выражение.
Желание иметь два определения X по своей сути является обязательным. На действительно декларативном языке у вас есть одно определение переменной в одной области. Поведение, которое вы хотите от Excel, соответствует редактированию программы.
Вы видели Resolver One? Это похоже на Excel с настоящим языком программирования.
Вот пример Даниэля в Python, так как я заметил, что вы сказали, что попробовали его на Python.
x = 10
y = 10
z = lambda: x + y
# Output: 20
print z()
x = 20
# Output: 30
print z()
Две вещи, которые вы можете посмотреть, это библиотека cells lisp, а Modelica язык динамического моделирования, оба из которых имеют отношения/уравнения.
Существует библиотека Lisp с таким поведением:
JavaFX сделает это для вас, если вы используете bind
вместо =
для 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
Вы можете сделать это в 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
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)
Можно также добавить автоматическую memoization для функций, но это намного сложнее, чем одна или две строки. http://blog.dinkla.net/?p=10
В F # несколько словесно:
let x = ref 10
let y = ref 20
let z () = !x + !y
z();;
y <- 40
z();;
Вы можете имитировать его в Ruby:
x = 10
y = 20
z = lambda { x + y }
z.call # => 30
z = 50
z.call # => 70
Не совсем то же, что вы хотите, но довольно близко.
Вы можете найти это видео (из Коммерческие пользователи Функциональное программирование) интересный и достойный просмотр. Если у вас есть довольно технофобные пользователи, это может быть хорошим подходом для вас.
не уверен, насколько хорошо метапост (1) будет работать для вашего приложения, но он декларативный.
Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
x = 10
y = 20
z = функция() возвращает x + y; конец
x = 50
= z()
70
Это не то, что вы ищете, но аппаратные описания Языки по определению являются "декларативными".
Этот код F # должен сделать трюк. Вы можете использовать ленивую оценку (объект System.Lazy), чтобы гарантировать, что ваше выражение будет оценено, когда это действительно необходимо, а не раньше.
let mutable x = 10;
let y = 20;
let z = lazy (x + y);
x <- 30;
printf "%d" z.Value