Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access outer variable inside a block and Y-combinator

I hope you all to be fine. I'm implementing the fixed-point Y-combinator in Harbour and I'm having some troubles with it. Well, the Y-combinator can be defined by the lambda-calculus as:

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

I'm trying to apply memoization with Y-combinator by performance questions. My current implementation is:

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 ) ) }

Basically, I can't use statements inside blocks, but I can use expressions and it works just fine. I'm avoiding an infinite recursion and the limit going through by 0 to infinite.

Until this time, it compiles just fine, but when I'm trying to access a variable of an outer block, Harbour kicks me in Face!

To test the Y-combinator implementation, I try to apply a simple implemetation of fibonacci sequence, but when I return a block that receives a parameter G and implicitly returns a block that receives a parameter N, G becames unavailable for me and the compiler says me that "Outer codeblock variable is out of reach".

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

This would also allow me to curry blocks. My question is: how can I access an outer variable inside a block, in Harbour?

like image 411
Marcelo Camargo Avatar asked Mar 16 '15 17:03

Marcelo Camargo


1 Answers

In Harbour, Clipper and xBase-based programming languages, blocks never can refer to the variable of the parent block. Blocks are not closures. We can reach that by creating local storages and using them in the internal blocks:

Function TestOuterScope
  Local accA
  Local bAdd := { |A| accA := A, { |B| accA + B } }
  Return Eval( Eval( bAdd, 10 ), 20 )
like image 124
Marcelo Camargo Avatar answered Nov 06 '22 06:11

Marcelo Camargo