# Can a function know its own name?

Posted 4 years ago
7230 Views
|
15 Replies
|
3 Total Likes
|
 Say I have a function: test[x_] := Block[{x}, ToExpression["test" <> "State"]; testState = 67] testState is a global that test can refer to to see its last state: In[133]:= testState Out[133]= 67 Test needs to be used repeatedly by renaming it test1, test2, etc.So, can test1 know its own name?
15 Replies
Sort By:
Posted 4 years ago
Posted 4 years ago
 Hi David,I've been poring over the MMA Boolean functions. As usual in MMA, there is more than you could have imagined available. Here is my Boolean thread that I will be augmenting soon: http://community.wolfram.com/groups/-/m/t/1257404The current state of the Boole functions is attached below. As you can see, I'm not a sophisticated user, but I'm learning a lot about MMA. I'll study your post and try manipulating things. Are you working with Boolean functions? You're the only responder so far who has mentioned the Boolean functions.Eric Attachments:
Posted 4 years ago
 Eric,You can take a look at the following. I think it gives a start on implementing the functionality that you desire. MMA has some nice Boolean logic functionality built in to make this easier.First, I create a characteristic equation for the JK FF. Then, create a BooleanFunction to implement the corresponding truth table: jkFFEqn = (j \[And] \[Not] q) || (\[Not] k \[And] q) jkFlipFlop = BooleanFunction[BooleanTable[jkFFEqn, {j, k, q}]] Confirm that the correct truth table is generated: TableForm[ Boole@BooleanTable[{j, k, q, jkFlipFlop[j, k, q]}, {j, k, q}], TableHeadings -> {None, {j, k, q, "q[n+1]"}}] This function will generate the transition to the next state. It requires that the flip flop to be transitioned be initialized to a known state. Note: I made some changes force the flip flop object state to be a Boolean value (True, False). This will make it unnecessary to convert (0, 1) values to (False, True) when chaining negated outputs to inputs. Clear[jkFlipFlopNextState] jkFlipFlopNextState[j_?(# == 0 || # == 1 &), k_?(# == 0 || # == 1 &), flipflopObj_Symbol, id_Integer] := jkFlipFlopNextState[j != 0, k != 0, flipflopObj, id] /; ValueQ[flipflopObj[id]] jkFlipFlopNextState[j_?(# == 0 || # == 1 &), k_?(# == False || # == True &), flipflopObj_Symbol, id_Integer] := jkFlipFlopNextState[j != 0, k, flipflopObj, id] /; ValueQ[flipflopObj[id]] jkFlipFlopNextState[j_?(# == False || # == True &), k_?(# == 0 || # == 1 &), flipflopObj_Symbol, id_Integer] := jkFlipFlopNextState[j, k != 0, flipflopObj, id] /; ValueQ[flipflopObj[id]] jkFlipFlopNextState[j_?(# == False || # == True &), k_?(# == False || # == True &), flipflopObj_Symbol, id_Integer] := (flipflopObj[id] = jkFlipFlop[j, k, flipflopObj[id]]) /; (flipflopObj[id] == False || flipflopObj[id] == True) To test, pick a name for your JK FF and a unique integer ID and an initial output (Q) state. I choose False as the initial state: jkFF[1] = False Then, run the state transition function. I generated some test input pairs (J, K) and mapped the transition function onto that list: TableForm[{#[[1]], #[[2]], Boole@jkFF[1], Boole@jkFlipFlopNextState[#[[1]], #[[2]],jkFF, 1]} & /@ Tuples[{0, 1}, 2], TableHeadings -> {None, {j, k, q, "q[n+1]"}}] You can add more JK's simply by initializing them like I did for jkFF[1], Like this, jkFF[2] = False (* This could be False or True *) jkFF[3] = True (* etc, etc *) Here's a JK FF configured as a toggler. jkFF[1] = False; Table[Boole@jkFlipFlopNextState[1,1, jkFF, 1], 10] Out[125]:= {1, 0, 1, 0, 1, 0, 1, 0, 1, 0} I didn't implement the clock since that seems to be a relatively simple extension to what I've done. If you desire, you can put all of this in a context (package) for localization. Hope this helps.
Posted 4 years ago
 Dear @Michael Rogers, with respect to this comment: The "Updating Name" is me. I get this every now and then. Does it happen to others? we are working on fixing this issue. A general recommendation is to always check, before you make a post, that you are still signed in into your Wolfram Community account, for example by reloading page and locating your name in the top right corner. Also do not leave Wolfram Community pages hang open for long time, - automated signing out happens due to security reasons. Apologies for the inconvenience.
Posted 4 years ago
 But the big problem is: Why doesn't Mathematica support static variables? Just a minor remark: On can easily mimic static variables like so: Module[{static = 1}, f[x_] := (static++) Sin[x] ] This way static is global for the function f[], but only for f[], and so it appears to be static. From outside the respective Module it cannot be seen. If I remember correctly I have this idea from @Leonid Shifrin.Best regards -- Henrik
Posted 4 years ago
 Hi Michael,I tried the code again on a fresh kernel. Still nothing. I mean it obviously works as in the third post on the thread. The Print statement is missing there. I'm running 10.3I'll study your code, but it's pretty advanced for me. Here is what I'm working on now: test[name_String] := Block[{state, A, B}, static[x_] := (ToExpression[name <> ToString[x]]); (* function to generate 'static' variables *) Evaluate@static[state] = 789; (* save the state *) state = static[state] (* retrieve the state *) ] In[18]:= test["jk2"] Out18]= 789 (* this is the global value retrieved *) In[19]:= jk2state (* this is the gloabal variable generated *) Out[19]= 789 Eric
Posted 4 years ago
 The "Updating Name" is me. I get this every now and then. Does it happen to others? One way to have a static variable is to use "subvalues" (definitions/calls of the form h[v1, v2,...][x]) to define methods on a data structure h[v1, v2,...]. Here's a simplified toggler. I use an Association for the data structure, but it could be any sort of variable. It's important to store the symbol and not its value in jk[s]. ClearAll[jk]; SetAttributes[jk, HoldAll]; (* must hold its arguments because s must be a Symbol in jk[s] *) jk[] := With[{s = Unique["s"]}, s = <|"state" -> 0|>; jk[s]]; (* creates new toggler *) jk[s_]["toggle"] := s["state"] = 1 - s["state"]; (* method to toggle state *) jk[s_]["state"] := s["state"]; (* method to return state *) jk1 = jk[] jk1["state"] (* jk[s260] the symbol s260 will be different each time *) (* 0 *) jk1["toggle"]; jk1["state"] (* 1 *) jk1["toggle"]; jk1["state"] (* 0 *) Since Mathematica does not have true local variables, the "static variable" is actually in the "Global" context: s260 (* <|"state" -> 0|> *) To further protect the "localization," it is common to put these such variables in a special context. One could, say, have a "jkdump" context: jk[] := With[{s = Unique["jkdumps"]}, s = <|"state" -> 0|>; jk[s]]; (* creates new toggler *) jk2 = jk[] (* jk[jkdumps13] *) jk2["toggle"] (* 1 *) s13 jkdumps13 (* s13 *) (* <|"state" -> 1|> *)  When I tried your original code, nothing happened. Just tried it again, still nothing. But it obviously works. When I run the code (from either my first or second post) on a fresh kernel, something happens, namely just what I showed. We must be running different things. Maybe you have a definition for test already in your kernel session or something like that. But I can't quite reconcile "nothing happened" with "it obviously works," so maybe you mean something else.
Posted 4 years ago
 Hi Neil,Using SystemModeler would defeat the purposes of this exercise which are to learn more about Mathematica and also to play around with Boolean algebra. I'd like to use the original algebra that Boole develops in An Investigation of the Laws of Thought. In it, he uses subtraction and division and elimination of variables from a system of equations. Of course, it has nothing to do with circuits--it's all about thought! But the big problem is: Why doesn't Mathematica support static variables?Hi Michael,When I tried your original code, nothing happened. Just tried it again, still nothing. But it obviously works. (Sorry for misspelling your name.)I suggested using a name in the fifth post down. This is the way to go--you're right, test1[] produces testState, not test1State.Eric
Posted 4 years ago
 Eric,Another all WMA way to do the FlipFlops is to avoid JK1=JKFlipFlop and do something like: JKFlipFlop[name_, otherArgs]:=... and use it JKFlipFlop["JK1", otherArgs] inside the definition you can do Set[Evaluate[Symbol[name <> "State"]], whateverYouWant] You can also use Unique[] to generate a new, unique symbol name.
Posted 4 years ago
 Eric,You can use Stack[] in the following way, it seems. The Condition (/;) is the key, since it is called before test[x] is replaced in the evaluation sequence. ClearAll[test] test[x_] := With[{stack = Stack[]}, Print[name = stack[[-2]]]; x /; True ]; test[x] (* test x *) I'm not sure what you mean that the earlier code doesn't work with test1 = test. If it's the following, I don't think it can work: test1 = test; test1[x] (* test x *) What happens with the standard evaluation is that the head is evaluated first. So test1[x] becomes test[x]. Then the function call is invoked. But now the function being called is test, not test1. So test will be on the evaluation stack.
Posted 4 years ago
 Eric,First of all. Just to explain Michael's code, there is nothing special about "call". He is using the pattern naming feature of the : symbol. Just as you can define Test[x_] is equivalent to Test[x:_] where the x:_ means "match anything and call it x". x_ is a shortcut for x : _ fun : Test[x_] means Match Test[_] and put the held value of the entire expression in fun and put the stuff inside the Test into x. The documentation on ":" can be found here and more info is in the docs about pattern matching which are referenced in that link.Secondly, I think you should consider Wolfram's SystemModeler (WSM) for your application. It will out of the box model JKFlipFlops and you can interact with it from Mathematica (WMA). In fact you can programmatically create models with flipflops and run the simulations from WMA and get the results back in WMA. Here is an example from WSM where they have a JKFlipFlop (which was modeled with two RS FlipFlops and some logic):Regards,Neil
Posted 4 years ago
 Hi Kuba,I'm writing an environment to play with Boolean objects. For example, here is a JK flip-flop: Of course, many flip-flops would be used, so I was thinking of naming each one as JK1, JK2, etc by equating JK1 = jkFlipFlop. The state of the flip-flop needs to be restored every time it is accessed. As Mathematica doesn't have static variables, I thought that if I could use the name of the flip-flop and add "State" to it, I could generate a global variable to hold the state. A not-very-elegant solution would be to have an input for the name. As Micheal's code above shows, it is possible to generate the state name. That would require putting the call: before each invocation of each flip-flop function, though.Maybe there is another way to do this. Any suggestions?Eric
Posted 4 years ago
 Can you elaborate on what is the final goal, desired usage and output for provided input?E.g. I don't know why test[x_] := Module[{testState}, whatever; testState = 67] does not fit your needs.
 Hi Micheal,Thanks for the reply. Sorry about that x; it's not necessary. I've tried your code, but I'm not getting the output you do--not getting anything.This works: In[95]:= call : test[] := Block[{}, name = Hold@call /. Hold[f_[___]] :> Hold[f]; Evaluate@ToExpression[ToString@ReleaseHold@name <> "State"] = 789; ] In[96]:= test[] In[98]:= testState Out[98]= 789 But it doesn't work with test1=test. That still produces testState as the global variable.I haven't seen that call: syntax before. Is that like a label?Thanks again, EricETA: Using Stack[] would seem to be the way to go, but test isn't on the stack. Any idea how to use the stack?
 Not sure exactly what you're after, but this sets name to the held head of the function call: call : test[x_] := Block[{x}, Print[name = Hold@call /. Hold[f_[___]] :> Hold[f]]; ToExpression["test" <> "State"]; testState = 67] test[a] (* Hold[test] 67 *) name (* Hold[test] *) Not sure what the Block[{x}..] is for nor the ToExpression. They seem extraneous or confusing.