June 2006 - Posts

Late-Bound Fixed Point

I wasn’t sure I was going to report a version of Y using Object rather than explicit recursive types, but it turned out to be so easy and pretty that I couldn’t resist. It’s rather a dead-end, evolutionarily speaking, since future development will use the template of the explicit Universal type presented last time, but it’s amusing enough for a blog entry:

 

REM (λ a -> z z a)

Class OfA

    Private Z As Object

    Sub New(ByVal Z As Object)

        Me.Z = Z

    End Sub

    Function [Of](ByVal a As Object) As Object

        Return Z.[Of](Z).[Of](a)

    End Function

End Class

 

REM [λ z -> h(λ a -> z z a)]

Class OfZ

    Private H As Object

    Sub New(ByVal H As Object)

        Me.H = H

    End Sub

    Function [Of](ByVal z As Object) As Object

        Return H.[Of](New OfA(z))

    End Function

End Class

 

REM y h = [λ z -> h(λ a -> z z a)] [λ z -> h(λ a -> z z a)]

Class Y

    Function [Of](ByVal h As Object) As Object

        Dim z As New OfZ(h)

        Return z.[Of](z)

    End Function

End Class

 

REM λ n -> if n=0 return 1 else return n * fact(n - 1)

Class OfN

    Private fact As Object

    Sub New(ByVal h As Object) REM inflate the closure

        Me.fact = h

    End Sub

    Function [Of](ByVal N As Object) As Object

        If N < 0 Then

            Return N

        End If

        If N = 0 Then

            Return 1

        Else

            Return N * fact.[Of](N - 1)

        End If

    End Function

End Class

 

REM Currying: λ g -> (λ n -> ...). This is our target for y.

Class f

    Function [Of](ByVal fact As Object) As Object

        Return New OfN(fact)

    End Function

End Class

 

Module Module1

    Sub Main()

        Dim y = New Y()

        Dim fact = y.[Of](New f)

        Dim result As Object = 1

        While result > 0

            Console.Write("Enter an Integer Number (negative to stop): ")

            result = fact.[Of](Console.ReadLine())

            Console.WriteLine("{0}", result)

        End While

    End Sub

End Module

Posted Tuesday, June 06, 2006 7:38 AM by brianbec | with no comments

Filed under: , ,

Finally Factorial Fixed Point

Ok, we have almost everything on hand to write a clean and honest recursion-free factorial in VB, albeit with recursive types. I actually struggled with this for some time, the problem being that we have functions of Long to Long—call those of type df, then functions from df to df—call those of type dh, then functions from dh to df, and functions from dh to dh—mmm, ok this situation isn’t converging. If we needed two flashes and one rolling thunderstorm of genius to get this far, it was looking like we might need a cat-3 hurricane of genius to get past it. Fortunately, my colleague, Mark Shields, showed me the way out. I’m not sure I would ever have thought of this myself, but it’s a lovely technique and it’s now added permanently to my bag of tricks. The technique is to model the type system itself—in miniature, of course—with a Universal type U that can model either a Long or a function from U to U. Now, all the variety of function types are swept up under one, large, inclusive rug. To model a Long, we’ll have a MustOverride ReadOnly Property that returns the Long value, and to model a function we’ll model function application itself through a MustOverride function named [Of] that takes a U and returns a U (square brackets let us reuse a keyword for our own purposes, and Of is the keyword for generic types, which we’re not using here for simplicity. We could have called the function appliedTo, but [Of] turns out to be definitely prettier, as we shall see):

 

MustInherit Class U

    MustOverride ReadOnly Property V() As Long

    MustOverride Function [Of](ByVal u As U) As U

End Class

 

Of course, we COULD use generics, replacing Long with a type variable T, but that’s a tweak at best. Let’s move on. For the subtype of U representing Long, we just need [Of] to throw:

 

Class I

    Inherits U

    Private i0 As Long

    Sub New(ByVal i As Long)

        i0 = i

    End Sub

    Overrides ReadOnly Property V() As Long

        Get

            Return i0

        End Get

    End Property

    Overrides Function [Of](ByVal x As U) As U

        Throw New ApplicationException( _

            "Sorry, can't apply a Long to an argument")

    End Function

End Class

 

The subtype of U that represents functions should be MustInherit itself, and, of course, should throw on attempted access of the Long property, which just doesn’t obtain for functions:

 

MustInherit Class λ

    Inherits U

    Overrides ReadOnly Property V() As Long

        Get

            Throw New ApplicationException( _

                "Sorry, can't get the value of a function")

        End Get

    End Property

End Class

 

Let’s start with the ultimate target for application of the y combinator. We called this f in the previous blogs on this theme. This is a function of two arguments, the first of which is the factorial function itself, the second of which is a Long number to which to apply factorial. Since we’re currying, we represent this as a function of a function that returns a function of a Long, represented in-turn by two subclasses of λ, remembering to make closures over free variables:

 

REM Currying: λ g -> (λ n -> ...). This is our target for y.

Class f

    Inherits λ

    Overrides Function [Of](ByVal fact As U) As U

        Return New OfN(fact)

    End Function

End Class

 

REM λ n -> if n=0 return 1 else return n * fact(n - 1)

Class OfN

    Inherits λ

    Private fact As λ

    Sub New(ByVal h As λ) REM inflate the closure

        Me.fact = h

    End Sub

    Overrides Function [Of](ByVal N As U) As U

        Dim i = N.V

        If i = 0 Then

            Return New I(1)

        Else

            Return New I(i * fact.[Of](New I(i - 1)).V)

        End If

    End Function

End Class

 

The money line is highlighted. Even though there is lots of machinery laying around, this is almost readable. Ok, now y itself, which we derived last time, with two auxiliary classes with closures, one for each of the lambda forms it uses internally:

 

REM y h = [λ z -> h(λ a -> z z a)] [λ z -> h(λ a -> z z a)]

Class Y

    Inherits λ

    Overrides Function [Of](ByVal h As U) As U

        Dim z As New OfZ_hFree(h)

        Return z.[Of](z)

    End Function

End Class

 

REM [λ z -> h(λ a -> z z a)]

Class OfZ_hFree

    Inherits λ

    Private H As U

    Sub New(ByVal H As U)

        Me.H = H

    End Sub

    Overrides Function [Of](ByVal z As U) As U

        Return H.[Of](New OfA_zFree(z))

    End Function

End Class

 

REM (λ a -> z z a)

Class OfA_zFree

    Inherits λ

    Private Z As U

    Sub New(ByVal Z As U)

        Me.Z = Z

    End Sub

    Overrides Function [Of](ByVal a As U) As U

        Return Z.[Of](Z).[Of](a)

    End Function

End Class

 

That’s it! We’re done, and we really just had to read off the mathematics. Wasn’t too hard once Mark showed me the road. By the way, if you change y so that it uses the following, divergent form, you can generate stack-overflows and check that we really do need the one with delayed application:

 

REM [λ z -> h(z z)] : Loops forever

Class OfZ_hFree_diverges

    Inherits λ

    Private H As U