Доступ к внешней переменной внутри блока и Y-комбинатора

Я надеюсь, что вы все в порядке. Я реализую Y-комбинатор с фиксированной точкой в ​​Harbour, и у меня с ним возникают проблемы. Что ж, Y-комбинатор можно определить с помощью лямбда-исчисления как:

Y = (λh.λF.F(λ x.((h(h))(F))(x))) (λh.λF.F(λ x.((h(h))(F))(x)))

Я пытаюсь применить мемоизацию с помощью Y-combinator по вопросам производительности. Моя текущая реализация:

Function YMem( bF, aCache )
   Local xAnswer
    If !lCache ; lCache := { } ; EndIf
    Return { |Arg| Iif( aCache[ Arg ] ;
        , /* then      */ aCache[ Arg ];
        , /* otherwise */ aCache[ Arg ] := ;
            Eval( Eval( bF, { |N| Eval( Eval( YMem, bF, aCache ), N ) } ), Arg ) ) }

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

До этого момента он компилировался просто отлично, но когда я пытаюсь получить доступ к переменной внешнего блока, Харбор пинает меня по лицу!

Чтобы проверить реализацию Y-комбинатора, я пытаюсь применить простую реализацию последовательности Фибоначчи, но когда я возвращаю блок, который получает параметр G, и неявно возвращает блок, который получает параметр N, G становится недоступным для меня, и компилятор говорит мне, что «Внешняя переменная кодового блока вне досягаемости».

Function Main
    Local bFib := YMem( { |G| ;
        { |N| ;
            Iif( N == 0, 1, Iif( N == 1, 1, Eval( G, N - 1 ) + Eval( G, N - 2) ) );
        } ;
    } )
    Return

Это также позволило бы мне каррировать блоки. Мой вопрос: как я могу получить доступ к внешней переменной внутри блока в Harbour?


person Marcelo Camargo    schedule 16.03.2015    source источник


Ответы (1)


В языках программирования на основе Harbour, Clipper и xBase блоки никогда не могут ссылаться на переменную родительского блока. Блоки не являются замыканиями. Мы можем достичь этого, создав локальные хранилища и используя их во внутренних блоках:

Function TestOuterScope
  Local accA
  Local bAdd := { |A| accA := A, { |B| accA + B } }
  Return Eval( Eval( bAdd, 10 ), 20 )
person Marcelo Camargo    schedule 19.08.2015