RE: Programming language difficulties.
- To: mathgroup at smc.vnet.net
- Subject: [mg38420] RE: [mg38382] Programming language difficulties.
- From: "Wolf, Hartmut" <Hartmut.Wolf at t-systems.com>
- Date: Sat, 14 Dec 2002 03:20:12 -0500 (EST)
- Sender: owner-wri-mathgroup at wolfram.com
>-----Original Message----- >From: Oliver Ruebenkoenig [mailto:ruebenko at donne.imtek.uni-freiburg.de] To: mathgroup at smc.vnet.net >Sent: Friday, December 13, 2002 10:10 AM >To: mathgroup at smc.vnet.net >Subject: [mg38420] [mg38382] Programming language difficulties. > > >Hi again Mathgroup ;-) > >This is a programming example from the wizard book chapter 3. >( http://mitpress.mit.edu/sicp/full-text/book/book.html ) > >Consider the following: > >withdraw := Evaluate[ > Module[ { balance = 100 }, > Function[ amount, > If[ balance >= amount, > balance -= amount; balance, > Print[ "Insufficient Funds" ] > ] > ] > ] > ] > >In[2]:= withdraw [ 60 ] > >Out[2]= 40 > >In[2]:= withdraw[ 60 ] >Insufficient Funds > >The question now is, can I in Mathematica write a function >that takes as >argument the balance, so that I do not have to use the fixed balance = >100. Note that in first example balance is _not_ present in the global >context. > >My idea was the following: > >secondWithdraw[ initBalance_ ] := Evaluate[ > Module[ { balance = initBalance }, > Function[ amount, > If[ balance >= amount, > balance -= amount; balance, > Print[ "Insufficient Funds" ] > ] > ] > ] > ] > >In[7]:= W1:=secondWithdraw[ 100 ] > >In[8]:= W1[ 60 ] >Out[8]= If[initBalance >= 60, balance$2 -= 60; balance$2, >> Print[Insufficient Funds]] > >So this however does not work. I _assume_ that Evaluate hits to early. >The evaluation of balance >= amount to initBalance >= amount is too >early. Is this the problem? How can I circumvent it? > >I'd be glad for any insights you might have. > > >Oliver Ruebenkoenig, <ruebenko at imtek.de> > Phone: ++49 +761 203 7293 > > Oliver, you'r quite right, dispense with that Evaluate: In[5]:= withdraw2[initBalance_] := Module[{balance = initBalance}, Function[amount, If[balance >= amount, balance -= amount; balance, Print["Insufficient Funds"]]]] In[11]:= W1 = withdraw2[100]; In[12]:= balance$21 Out[12]= 100 In[13]:= W1[60] Out[13]= 40 In[14]:= W1[60] >From In[14]:= "Insufficient Funds" The example from the wizard book, in fact is no good at all, just construed to bewilder little children. Your idea to create an account, an individual object, is much better. However other methods should be defined, and the constructor given a different name. Here is something containing several "member functions": In[177]:= Remove[createAccount] In[178]:= createAccount /: Set[thisAccount_, createAccount[initial_:1 ]] := (thisAccount = Module[{account, key = Random[Integer, {0, 10^12}]}, With[{key = key}, account[Balance] := SequenceForm[account[key], "\[ThinSpace]\[InvisibleComma]\[InvisibleComma]", EUR]; account[key] = initial; account[Withdraw] = (If[account[key] >= #, (account[key] -= #)EUR, Print["Insufficient Funds"]; $Failed]) &; account[Deposit] = (account[key] += #; If[account[key] > 10^6, Print["Beware of Taxes!"]]; account[key]EUR) &; account]];) In[179]:= myAccount = createAccount[] -- this calls the constructor with default initial balance (a donation from my bank), no output is given In[180]:= ?myAccount Global`myAccount myAccount = account$154 -- that's the object created In[181]:= ?account$154 .... -- you see what's behind the scene In[182]:= myAccount[Balance] Out[182]= 1 EUR -- method Balance shows the initial donation In[183]:= myAccount[Deposit][60] Out[183]= 61 EUR In[184]:= myAccount[Balance] Out[184]= 61 EUR In[185]:= myAccount[Withdraw][50] Out[185]= 11 EUR In[186]:= myAccount[Withdraw][50] >From In[186]:= "Insufficient Funds" Out[186]= $Failed In[187]:= myAccount[Deposit][10^7] >From In[187]:= "Beware of Taxes!" Out[187]= 10000011 EUR Perhaps it is better to move the methods to a class (and just fix the parameters): In[206]:= Remove[createAccount, Balance, Withdraw, Deposit] In[207]:= createAccount /: Set[thisAccount_, createAccount[initial_:1 ]] := (thisAccount = Module[{account, key = Random[Integer, {0, 10^12}]}, account[key] = initial; With[{key = key}, account[Balance] := Balance[account, key]]; account[Withdraw] = Withdraw[account, key]; account[Deposit] = Deposit[account, key]; account];) In[212]:= Balance[account_, key_] := SequenceForm[account[key], "\[ThinSpace]", EUR] In[213]:= Withdraw[account_, key_][amount_] := (If[account[key] >= amount, (account[key] -= amount)EUR, Print["Insufficient Funds"]; $Failed]) In[214]:= Deposit[account_, key_][amount_] := (account[key] += amount; If[account[key] > 10^6, Print["Beware of Taxes!"]]; account[key]EUR) The key isn't necessary, consider it as a password (from the bank not from you! and it doesn't matter if someone else has the same password) Of course we have to hide Information, however I couldn't succeed as my definition... Evaluate[account] /: Information[account, ___] := "gotcha!"; ...prevented Information["account$154"] but not Information["account$154", LongForm -> True] or Information["account$154", LongForm -> False] ...wasn't effective. The explanation for that certainly is quite complicated, so I have to state: with Mathematica you can reach for any money (and any password for that matter)! -- Hartmut Wolf