تعبيرات لامدا في دلفي بريزم / الأكسجين
سؤال
لقد قمت بتجربة تعبيرات لامدا في الأكسجين.تعبير لامدا العودي البسيط جدًا لحساب رقم فيبوناتشي:
var fib : Func<int32, int32>;
fib := n -> iif(n > 1, fib(n - 1) + fib(n - 2), n);
fib(3);
عندما أقوم بتشغيل هذا الرمز أحصل على استثناء nullreference.أي أفكار حول ما أفعله خطأ؟
المحلول
وأنت لم تفعل شيئا خاطئا. إذا كان أي شيء، يجب على المترجم يحذرك حول استخدام أكذوبة، متغير غير معين، داخل الجسم لامدا.
ولكن المترجم يجب أن التقاط أكذوبة كموقع، بحيث عندما يكمل المهمة ويتم استدعاء مندوب في وقت لاحق، تم تعيينه بشكل صحيح أكذوبة ويجب أن تعمل العودية كما هو متوقع.
والسبب الأكثر وضوحا من الممكن للفشل هو أن بريزم لا التقاط المواقع، ولكن القيم، التي ستكون unintuitive بشكل فاضح وعلى خلاف مع كل تنفيذ إغلاق آخرين في لغات غير نقية.
وعلى سبيل المثال، حاول هذا الرمز في جافا سكريبت (مخالف للتأكيد كريج في تعليقات على هذه الوظيفة، وجافا سكريبت أيضا يلتقط المواقع، وليس القيم):
<html>
<head>
<script language='javascript'>
function main()
{
var x = 1;
var f = function() { return x; };
alert(f());
x = 2;
alert(f());
}
</script>
</head>
<body>
<input type=button onclick="javascript:main()"></input>
</body>
</html>
ومربعات حالة تأهب بعد النقر على زر إظهار 1 و 2 على التوالي، في حين التالية دلالات بريزم / الأكسجين فإنها تظهر 1 في المرتين.
نصائح أخرى
وستيف:
وعلى ما يبدو تم تناول مسألة في دلفي بريزم 2010. وتعمل نموذج التعليمات البرمجية التالية في الافراج عن مسؤول.
var fib : Func<int32, int32>;
fib := n -> iif(n > 1, fib(n - 1) + fib(n - 2), n);
var i := fib(9); //1,1,2,3,5,8,13,21,34
MessageBox.Show(i.ToString);
ووMESSAGEBOX يظهر القيمة 34.
وردا على سؤال جيرون، تم تشغيل هذا الرمز في النص الأصلي، بناء الافراج عن مسؤول، 3.0.21.661.
وكحل مؤقت يمكنك استخدامها:
var f := new class(f: Tfib := nil);
f.f := method(n : Int32): Int32
begin
if n > 1 then
Result := f.f(n-1) + f.f(n-2)
else
Result := n;
end;
f.f(3);
وبريزم يعالج القبض على المتغيرات المحلية بشكل مختلف ثم أصلي دلفي أو C #. في تلك 2 سيتم تعيين جميع الإشارات في التعليمات البرمجية تلك السكان المحليين إلى حقول من الفئة التي تم إنشاؤها مترجم التي ستعقد طريقة دون الافصاح عن هويتك. في المنشور، هذه السكان المحليين البقاء السكان المحليين العاديين، ولكن يتم تعيين مجالات هذه الحقول المخفية عند مثيل طريقة المجهول.
واحد طريقة للحصول على امدا العودية، سيكون لاستخدام نوع مرجع لعقد امدا بالنسبة لك.
كل هذا يبدو أكثر تعقيدا بكثير ثم هو عليه حقا.
2 طرق لإنجاز هدفك:
1)
var fib := new class(Call : Func<Integer, Integer> := nil);
fib.Call := n -> iif(n > 1, fib.Call(n - 1) + fib.Call(n - 2), n);
var x := fib.Call(3);
2) عندما كنت لا تريد أن يكون إشارة إلى هذا المجمع، يمكنك أن تفعل ذلك كما يلي:
var fib : Func;
with fibWrapper := new class(Call : Func<Integer, Integer> := nil) do
begin
fibWrapper.Call := n -> iif(n > 1, fibWrapper.Call(n - 1) + fibWrapper.Call(n - 2), n);
fib := fibWrapper.Call;
end;
وراجع للشغل، والسبب وراء بريزم عدم اتباع C # هنا، هو أن للخيوط وحلقة، وهذا إعادة استخدام فار القبض يجعل لمشاكل وقت التشغيل غريبة الصعبة. في بريزم، وألقت القبض على يلتقط حقا لحظة تعيين طريقة مجهول أو امدا. الذي لديه لمسة immuatble معين لذلك ...
وابتهاج، روبرت
هل ينطبق الأمر نفسه على الأساليب المجهولة؟أعتقد أنه كذلك، لكن لا يمكنني معرفة بناء الجملة لتشغيل هذا
var f : Tfib;
f := method(n : Int32): Int32
begin
if n > 1 then
Result := f(n-1) + f(n-2)
else
Result := n;
end;
يحرر
نعم هو كذلك.
var f := new class(call : TFib := nil);
f.call := method(n : Int32): Int32
begin
if n > 1 then
Result := f.call(n-1) + f.call(n-2)
else
Result := n;
end;
لقد حاولت أيضًا تعيين المتغير:
var fib : Func<int32, int32> := nil;
fib := n -> iif(n > 1, fib(n - 1) + fib(n - 2), n);
fib(3);
لا يزال دون حظ.
بدافع الفضول حاولت شيئًا مشابهًا باستخدام طرق مجهولة.
لقد قمت بشكل أساسي بتنفيذ بحث متعمق أولاً على رسم بياني غير دوري مباشر باستخدام طريقة مجهولة متكررة:
var dfs : dfsmethod;
dfs := method(Vertex : IVertex)
begin
var IsDone : Boolean;
Visited[Vertex.Key] := True;
aMethod(Vertex.Key, Vertex.Weight, var IsDone); //PreVisit
if IsDone then Exit;
for each Successor in Vertex.Successors do
if not Visited[Successor.Key] then
dfs(Successor);
end;
dfs(InternalGetVertex(aStart));
تم تجميع هذا، ولكن حصلت على نفس الخطأ.NullReferenceException.
لقد حاولت أيضًا إعادة تنفيذ فيبوناتشي كطريقة مجهولة متكررة:
var f : Tfib;
f := method(n : Int32): Int32
begin
if n > 1 then
Result := f(n-1) + f(n-2)
else
Result := n;
end;
f(3)
مرة أخرى نفس المشكلة!دائمًا في التكرار الثاني (أيأول مكالمة متكررة)