tag:blogger.com,1999:blog-2564777502681463717.post5064063170271533901..comments2023-12-31T10:17:57.560-05:00Comments on Teaching, Playing, and Programming: Functional Programming in...Ada?Chris Okasakihttp://www.blogger.com/profile/18247315355264748920noreply@blogger.comBlogger6125tag:blogger.com,1999:blog-2564777502681463717.post-87782792477375739232008-07-08T21:14:00.000-04:002008-07-08T21:14:00.000-04:00Thank you, gelisam and stefan, for your OO version...Thank you, gelisam and stefan, for your OO versions.Chris Okasakihttps://www.blogger.com/profile/18247315355264748920noreply@blogger.comtag:blogger.com,1999:blog-2564777502681463717.post-23715310760672345492008-07-08T15:16:00.000-04:002008-07-08T15:16:00.000-04:00That was fun! I'll present the idea in my own lect...<EM>That was fun! I'll present the idea in my own lecture (on programming in Ada).</EM><BR/><BR/><EM>As for the challenge of an object-oriented approach -- here is one (in Ada, of course). First, package Fun declares two abstract classes for the monitors and for the function we observe (the "suspect"):</EM><BR/><BR/>package Fun is<BR/><BR/>type Suspect;<BR/><BR/>type Monitor is abstract tagged null record;<BR/><BR/>function Recu(<BR/> Self: access Monitor;<BR/> W: Suspect'Class;<BR/> X: Integer) return Integer<BR/> is abstract;<BR/><BR/>type Suspect is abstract tagged null record;<BR/><BR/>function Exec(<BR/> Self: Suspect;<BR/> C: access Monitor'Class;<BR/> X: Integer) return Integer<BR/> is abstract;<BR/><BR/>end Fun;<BR/><BR/><EM>As you can see, monitors have a method Recu, and suspects a method Exec. </EM><BR/><BR/><EM>One of the benefits of using the name Fun for the above package is that now we will write</EM> with Fun; <EM>in all packages which use Fun. I like that.</EM><BR/><BR/><EM>Next, the Fibonacci function, derived from Suspect.</EM><BR/><BR/>with Fun;<BR/>package Fib is<BR/><BR/>type Obj is new Fun.Suspect with null record;<BR/> <BR/>overriding<BR/>function exec(<BR/> This: Obj;<BR/> C: access Fun.Monitor'Class;<BR/> X: Integer) return Integer;<BR/><BR/>end Fib;<BR/><BR/>--- above the interface spec<BR/>--- below the implementation<BR/><BR/>with Fun;<BR/>package body Fib is<BR/><BR/>overriding<BR/>function Exec(<BR/> This: Obj; ... ) return Integer is<BR/>begin<BR/> if X <= 1 then<BR/> return 1;<BR/> else<BR/> return <BR/> C.Recu(This, X-1) + C.Recu(This, X-2);<BR/> end if;<BR/>end Exec;<BR/><BR/>end Fib;<BR/><BR/><EM>Finally, the monitors:</EM><BR/><BR/>with Fun;<BR/><BR/>package Some_Monitors is<BR/><BR/>type Depth is new Fun.Monitor with<BR/> record<BR/> Current: Natural := 0;<BR/> Max: Natural := 0;<BR/> end record;<BR/><BR/>overriding<BR/>function Recu(<BR/> Mon: access Depth;<BR/> F: Fun.Suspect'Class;<BR/> X: Integer) return Integer;<BR/><BR/>type Mem_Type is array (Integer range <>) of Integer;<BR/>type Mem_Used is array (Integer range <>) of Boolean;<BR/><BR/>type Memoize (Low, High: Integer) is<BR/> new Fun.Monitor with<BR/> record<BR/> Memory: Mem_Type (Low .. High);<BR/> Used : Mem_Used (Low .. High)<BR/> := (others => False);<BR/> end record;<BR/>overriding<BR/>function Recu(<BR/> Mon: access Memoize;<BR/> F: Fun.Suspect'Class;<BR/> X: Integer) return Integer;<BR/><BR/>end Some_Monitors;<BR/><BR/>-- that was the spec<BR/>-- now the implementation<BR/><BR/>with Fun;<BR/>package body Some_Monitors is<BR/><BR/>overriding<BR/>function Recu(Mon: access Depth;<BR/> ...) return Integer is<BR/> Result: Integer;<BR/>begin<BR/> Mon.Current := Mon.Current + 1;<BR/> if Mon.Current > Mon.Max then<BR/> Mon.Max := Mon.Current;<BR/> end if;<BR/> Result := F.Exec(Mon, X);<BR/> Mon.Current := Mon.Current - 1;<BR/> return Result;<BR/>end Recu;<BR/><BR/>overriding<BR/>function Recu(<BR/> Mon: access Memoize;<BR/> ...) return Integer is<BR/><BR/>begin<BR/> if X in Mon.Memory'Range then<BR/> if not Mon.Used(X) then<BR/> Mon.Memory(X) := F.Exec(Mon, X);<BR/> Mon.Used(X) := True;<BR/> end if;<BR/> return Mon.Memory(X);<BR/> else<BR/> return F.Exec(Mon, X);<BR/> end if;<BR/>end Recu;<BR/><BR/>end Some_Monitors;<BR/><BR/><EM>Sorry for the length of this message. Ada is a bit on the verbose side ;-)</EM>stefan luckshttps://www.blogger.com/profile/08758912165729126244noreply@blogger.comtag:blogger.com,1999:blog-2564777502681463717.post-22869951184615335232008-07-04T15:25:00.000-04:002008-07-04T15:25:00.000-04:00Yeah, I figured this out too while trying to imple...Yeah, I figured this out too while trying to implement my solution (not in Ada, mind you). My latest attempt combines decorators with the strategy pattern as follows.<BR/><BR/>Each strategy defines a call(f, x) and a recur(f, x) method, both of which possibly perform monitoring actions before returning f.body(x). Each monitor decorates a strategy with extra monitoring actions.<BR/><BR/>Each monitorable function is parameterized by a strategy, which is used in the body() method to perform nested calls to body().<BR/><BR/>Superclasses for monitors and monitorable functions allow the boilerplate to be minimized, as the following usage sample shows.<BR/><BR/>class Fib(Function):<BR/> def body(self, x):<BR/> if x <= 1:<BR/> return 1<BR/> else:<BR/> return self.recur(x-1) + self.recur(x-2)<BR/><BR/>class Count(Monitor):<BR/> def call(self, function, *args):<BR/> self.count = 1<BR/> r = self.inner.call(function, *args)<BR/> print "call count: " + str(self.count)<BR/> return r<BR/> def recur(self, function, *args):<BR/> self.count += 1<BR/> return self.inner.recur(function, *args)<BR/><BR/>class Memo(Monitor):<BR/> def call(self, function, *args):<BR/> self.memo = {}<BR/> return self.inner.call(function, *args)<BR/> def recur(self, function, *args):<BR/> if not self.memo.has_key(args):<BR/> self.memo[args] = self.inner.recur(function, *args)<BR/> return self.memo[args]<BR/><BR/>plain_fib = Fib(Call())<BR/>mc_fib = Fib(Memo(Count(Call())))<BR/><BR/>print plain_fib(10)<BR/>print mc_fib(10)gelisamhttps://www.blogger.com/profile/10619127479176568208noreply@blogger.comtag:blogger.com,1999:blog-2564777502681463717.post-62137085405481238722008-07-04T13:31:00.000-04:002008-07-04T13:31:00.000-04:00gelisam: The decorator pattern is certainly close,...gelisam: The decorator pattern is certainly close, but I don't think it's quite the same thing because of the recursion. That is, with vanilla decorators, the wrapper would be invoked for the top-level method call, but not for the inner, recursive calls.Chris Okasakihttps://www.blogger.com/profile/18247315355264748920noreply@blogger.comtag:blogger.com,1999:blog-2564777502681463717.post-87272495667149115122008-07-04T00:57:00.000-04:002008-07-04T00:57:00.000-04:00"a truly object-oriented approach to solving the s..."a truly object-oriented approach to solving the same problem": wouldn't decorators be a perfect match?gelisamhttps://www.blogger.com/profile/10619127479176568208noreply@blogger.comtag:blogger.com,1999:blog-2564777502681463717.post-34387232687575283752008-07-03T15:41:00.000-04:002008-07-03T15:41:00.000-04:00You can use the unsafe version of 'access to ignor...You can use the unsafe version of 'access to ignore the scope restrictions, but as it doesn't magically give Ada closures I don't think it would make much of a difference :-)Harald Korneliussenhttps://www.blogger.com/profile/02909854185625282505noreply@blogger.com