I need a function that takes the name of a symbol as a string and returns whether that symbol is already defined. The function ValueQ is close but it returns False for function names. Also, it takes symbols rather than strings.
Examples:
defined["N"] --> True (predefined function N)
defined["x"] --> False
x = 7;
defined["x"] --> True (x is now defined)
defined["7"] --> True (7 is a number)
f[x_] := 2x
defined["f"] --> True (f has DownValues)
g[x_][y_] := x+y
defined["g"] --> True (g has SubValues)
PS: Thanks to Pillsy for pointing out the need to check for both DownValues and SubValues.
I cobbled this together, which seems to work:
defined[s_] := ToExpression["ValueQ[" <> s <> "]"] ||
Head#ToExpression[s] =!= Symbol ||
ToExpression["Attributes[" <> s <> "]"] =!= {} ||
ToExpression["DownValues[" <> s <> "]"] =!= {} ||
ToExpression["SubValues[" <> s <> "]"] =!= {}
Hopefully there's a prettier solution.
PS: Thanks to Pillsy for pointing out the need to check for both DownValues and SubValues.
I think Names should do the trick:
Names["string"] gives a list of the
names of symbols which match the
string.
If Names["foo"] returns {}, then there should be no definitions for foo, otherwise it should return {"foo"}.
So your function 'defined' might be done as:
defined[str_] := Names[str] != {}
For symbols at least, because this doesn't work for "7", since 7 is not a symbol. You could handle this case seperately, for instance with NumberQ.
Also, you can use Symbol to make a symbol out of a string (useful for automatically generating symbols) and Definition to check the definitions of a symbol.
Symbol["name"] refers to a symbol with
the specified name.
Definition[symbol] prints as the
definitions given for a symbol.
EDIT: Better than looking at what Names returns, NameQ["name"] tells you if a given name exists. Still doesn't tell you if the symbol has an explicit definition though, just that it has been mentioned.
You can use DownValues to see if you have "functions" associated with a symbol. This will work for definitions like
f[x_, y_] := x + y
or
g[3] = 72 * a;
It won't work for exotic things like
h[a_][b] = "gribble";
but most people won't think of that as defining a function anyway. If you want to check for the existence of a function definition, you need to convert the name to an expression (and make sure it's wrapped in Hold when you do!). Here's a reasonably robust function that checks for both DownValues and SubValues:
functionNameQ[name_String] :=
With[{ hSymbol = ToExpression[name, InputForm, Hold] },
MatchQ[hSymbol, Hold[_Symbol]] &&
((DownValues ## hName) =!= {} || (SubValues ## hName) =!= {})];
defined[str_] := Not[ToString[FullDefinition[str]] === ""]
Related
I'm not entirely sure what I'm doing wrong here. I have tested the code by input and output and it functions as desired no pun intended. :'P
I'm just not setting up this function correctly and I believe it's because my arguments happen to be desirably a string. Where if done correctly "CD" will be inserted into the middle of "ABEF". So, how do I go about doing this?
Thanks!
insertstr(ABEF, CD)
Function insertstr(string1, string2)
nostrmsg = "No string"
fullng = len(string1)
half = len(string1)/2
if half>0 then hfstr1 = mid(string1, 1, half)
str2lng = len(string2)
if str2lng>0 then paste = hfstr1+string2
lshalf = mid(string1, half+1, fullng)
if str2lng+half=str2lng+half then insert = paste+lshalf
End Function
Start with the knowledge that a functions returns a value, a tentative specification of what the function should do, and a basic testing skeleton:
Option Explicit
' returns the string build by inserting m(iddle) into f(ull) at half position
Function insertInto(f, m)
insertInto = "?"
End Function
Dim t, r
For Each t In Array( _
Array("ABEF", "CD", "ABCDEF") _
)
r = insertInto(t(0), t(1))
WScript.Echo t(0), t(1), r, CStr(r = t(2))
Next
output:
cscript 26873276.vbs
ABEF CD ? False
Then learn about Left, Mid, Len, and \ (integer division).
At last, re-write insertInto() so that the result starts with
cscript 26873276.vbs
ABEF CD ABCDEF True
The script passes two parameter values to another instance of the script. So the built-in parameter variable, 0, contains the number of passed parameters. 1 is in the below example "C:/Windows" and 2 is "/switchtest"
It is possible to assign the parameter values to strParam1 and strParam2 with the traditional method outside the function (with the single equal sign). However, inside a function, the assignments fail.
If they are assigned in a loop with the := sign, it seems to work.
Why is it? Can anybody explain this behavior?
strParam1 = %1%
strParam2 = %2%
msgbox, 64, Outside the Function, number of parameters:%0%`npath: %strParam1%`nswitch: %strParam2%
test_params()
strPath := "C:/Windows"
strSwitch := "/switchtest"
RunWait "%A_AhkPath%" "%A_ScriptFullPath%" "%strPath%" "%strSwitch%"
test_params() {
global 0
; this works
; loop %0%
; strParam%A_Index% := %A_Index%
; this causes an error: "This dynamic variable is blank. If this variable was not intended to be dynamic, remove the % symbols from it."
; strParam1 := %1%
; strParam2 := %2%
; this passes empty values; however, this method works outside the function.
strParam1 = %1%
strParam2 = %2%
msgbox, 64, Inside the Function, number of parameters:%0%`npath: %strParam1%`nswitch: %strParam2%
if strParam2
exitapp
}
You had the right idea with global 0; that allows %0% to carry into the function from toplevel. You just need to declare global 1, 2 as well.
Even if you do this, you can't use := to assign them to variables, because := deals with expressions and there is no syntax to use them in expressions (normally a variable is referred to in an expression with the variable name alone, without %%; obviously 1 and 2 are interpreted as actual numbers instead of variables).
#echristopherson answered the question, but I'd like to propose a workaround. This assumes you're using AutoHotkey_L.
If you run the test script with the args "a b c", it gives you this.
3
1, a
2, b
3, c
The test:
argv := args()
test := argv.MaxIndex() "`n"
for index,param in argv
test .= index ", " param "`n"
MsgBox % test
And the function:
args() {
global
local _tmp, _out
_out := []
Loop %0% {
_tmp := %A_Index%
if _tmp
_out.Insert(_tmp)
}
return _out
}
I want to check if an address starts with http://www.youtube.com.
If I have something like this
if rs("mainVideoName")="http://www.youtube.com*" then
This doesn't work, so how can I do it?
Try this:
Function UrlStartsWith(string1, string2)
UrlStartsWith = InStr(1, string1, string2, 1) = 1
End Function
If UrlStartsWith(rs("mainVideoName"), "http://www.youtube.com") Then
End If
Starts with is tested by using IntStr and ensuring that it returns 1 as the starting position that the search string is found. Since you are testing a URL the code above uses a TextCompare to make insensitive to case.
You can use the InStr() function for this:
Dim positionOfMatchedString
positionOfMatchedString= InStr(rs("mainVideoName"),"http://www.youtube.com")
If positionOfMatchedString > 0 Then
// Do your stuff here
End If
As Anthony points out, this tells you that string2 is contained in string1. You could write it as:
If positionOfMatchedString = 1 Then
to check for it beginning with.
How about...
Dim s: s = "http://www.youtube.com"
Dim l: l = Len(s)
If Left(rs("mainVideoName"), l) = s Then
' String begins with URL part '
End If
I had something like the following in my notebook.
test1[g_] := (g == 5);
test2[g_] := (g == 6);
tests={"test1", "test2"}
ToExpression[#][5] & /# tests
When I put this code in a package it doesn't work because test1 is now called MyPackage'Private'test1. How can I modify the last line to make this code run both inside package and inside notebook?
Update
Here's why I was doing doing ToExpression as opposed to using Symbols. In retrospect, maybe it's easier to use Symbols instead
I had a function which I call like getGraphs["LeafFree","Planar",!"Tree",...] to get all graphs that are leaf free, planar and not trees. Some of those strings are classes in GraphData, while others were my own classes. For each of my own classes I had a function with identical name, like LeafFree that tested the property. In the notebook, using ToExpression code like above was the quickest way to implement this.
getGraphs[n_Integer, cl__] := getGraphs[{n, n}, cl];
getGraphs[{nmin_Integer, nmax_Integer}, cl__] :=
Module[{maxgraphnum = 100},
customClasses = {"isLeafFree", ! "isLeafFree"};
classes = {cl}\[Backslash]customClasses;
builtinClasses =
GraphData["Classes"] \[Tilde] (Not /# GraphData["Classes"]);
Assert[classes \[Subset] builtinClasses];
isLeafFree[gname_] :=
FreeQ[GraphData[gname, "DegreeSequence"], 0 | 1];
posClasses = Cases[classes\[Backslash]customClasses, _String];
posGroup =
If[posClasses == {}, GraphData[nmin ;; nmax],
GraphData[posClasses, nmin ;; nmax]];
negClasses = classes\[Backslash]posClasses;
negGroups = GraphData[#[[1]], nmin ;; nmax] & /# negClasses;
result = Complement[posGroup, Sequence ## negGroups];
customTest[g_] :=
And ## (ToExpression[#][g] & /# ({cl} \[Intersection]
customClasses));
(*result=Take[result,Min[Length[result],100]];*)
result = Select[result, customTest]
]
I agree with the comments above that you should perhaps have a compelling reason to do this, but here goes. Here is a code I use in such cases, which allows your symbol to be parsed in whatever context you like, at run-time:
SetAttributes[ParseTimeNameSpaceWrapper,HoldFirst];
Options[ParseTimeNameSpaceWrapper] = {
LocalizingContext->"MyLocalizingContext`",
DefaultImportedContexts:>{"Imported1`", "Imported2`"},
ExtraImportedContexts:> {}
};
ParseTimeNameSpaceWrapper[code_,opts:OptionsPattern[]]:=
Module[{result,
context = OptionValue[LocalizingContext],
defcontexts = OptionValue[DefaultImportedContexts],
extraContexts = OptionValue[ExtraImportedContexts],
allContexts},
allContexts = {Sequence##defcontexts,Sequence##extraContexts};
BeginPackage[context,If[allContexts==={},Sequence##{},allContexts]];
result = code;
EndPackage[];
result
];
You can use options to specify some contexts where these symbols exist, that you want to import during the parse stage. You can call this from any package or notebook, and the symbol will be parsed according to whatever context you specify.
HTH
Edit:
Responding to a comment (since it made the question more specific): There is no question that at run-time Context[] will display whatever is the current context from where the function was called (Global in that case). I meant something else: Context has a syntax Context[symbol], to give a context of any symbol if it is on the $ContextPath. For example, Context[getGraphs] returns Bulatov'showGraphs'. Therefore, if you need to determine the context of some exported function automatically, you call Context[function]. You can use this to construct full names of other (private) functions of that package. Here is a self - contained example:
In[1]:=
BeginPackage["MyTest`"];
f[x_, y_, context_: Context[f]] :=
Module[{f1str = "function1", f2str = "function2", f1, f2},
{f1, f2} = ToExpression[context <> "Private`" <> #] & /# {f1str, f2str};
f1[x, y];
f2[x, y];];
Begin["`Private`"];
function1[x_, y_] := Print["In function1: arguments are ", x, " , ", y];
function2[x_, y_] := Print["In function2: arguments are ", x, " , ", y];
End[]
EndPackage[];
Out[6]= "MyTest`Private`"
In[8]:= f[1, 2]
During evaluation of In[8]:= In function1: arguments are 1 , 2
During evaluation of In[8]:= In function2: arguments are 1 , 2
where x,y are just some sample arguments. Then, you never actually supply the last argument, but you can use the context variable inside your function, to construct long names for your other functions, as in the sample code above. Or you could just plain use Context[f] inside body of the function, and not add any arguments to it.
ToExpression uses the current binding of $Context when creating symbols, so you can force your expression to be interpreted within a particular context thus:
Block[{$Context="MyPackage`Private`"}, ToExpression[#][5]] & /# tests
I'm not sure I understand the circumstances of the original question. You can get the current context using $Context or Context[]... but ToExpression will automatically use the current context without intervention.
If I run the exhibited code in a notebook, it works fine. If I run it like this:
Begin["MyPackage`Private`"]
test1[g_] := (g == 5);
test2[g_] := (g == 6);
tests = {"test1", "test2"}
ToExpression[#][5] & /# tests
End[]
... it also works fine. I can get it to fail if I run it like this:
(* in the package file *)
Begin["MyPackage`Private`"]
test1[g_] := (g == 5);
test2[g_] := (g == 6);
End[]
(* in the notebook *)
tests = {"test1", "test2"}
ToExpression[#][5] & /# tests
... which not only fails but also creates spurious symbols in the notebook's context. You can work around this problem using the Block recipe from above.
If you want to capture the context that was in effect at the moment the package code was loaded, you can do something like this:
(* in the package *)
Begin["MyPackage`Private`"]
test1[g_] := (g == 5);
test2[g_] := (g == 6);
tests = {"test1", "test2"};
With[{context = $Context},
runTests[] := Block[{$Context = context}, ToExpression[#][5]] & /# tests
]
End[]
(* in the notebook *)
MyPackage`Private`runTests[]
runTests uses With to inject the private package context into its definition.
As Janus' noted, it is better to use symbols than strings since they automatically manage the whole context issue -- but this assumes your actual use case will permit the use of symbols.
I'd like to be able to do s'Graph and c'Graph to refer to System'Graph and Combinatorica'Graph (and other functions conflicting with Combinatorica) is there a way to do this?
Following Simon's idea, the following seems to work
{Set ## {ToExpression["c" <> Last[StringSplit[#, "`"]]],
ToExpression[#]}} & /# Names["Combinatorica`*"];
{Set ## {ToExpression["s" <> Last[StringSplit[#, "`"]]],
ToExpression[#]}} & /# Names["System`*"];
Now cCompleteGraph[5] and sCompleteGraph[5] return Combinatorica and System graphs respectively
Update Jan 8th
For future reference, this is the method I ended up using to use GraphUtilities, Combinatorica and built-in graph functionality together. It resolves conflict by remapping all combinatorica functions like Graph to cGraph and changes $Post to remove GraphUtilities and Combinatorica from ContextPath on each evaluation, necessary because GraphUtilities'ToCombinatoricaGraph adds Combinatorica to $ContextPath at every call.
To summarize, execute the code below at start of each session. Combinatorica func is now cfunc, GraphUtilities func is GraphUtilities'func, and built-in func is just func
Needs["Combinatorica`"];
combNames = Names["Combinatorica`*"];
{Set ## {ToExpression["c" <> Last[StringSplit[#, "`"]]],
ToExpression[#]}} & /# Names["Combinatorica`*"];
Needs["GraphUtilities`"];
$ContextPath = DeleteCases[$ContextPath, "Combinatorica`"];
$Post = ($ContextPath =
DeleteCases[$ContextPath,
"Combinatorica`" | "GraphUtilities`"]; #) &;
Something like:
$PreRead = # /. {str_String :>
StringReplace[
str, {RegularExpression["^s`(.*)"] :> "System`" <> "$1",
RegularExpression["^c`(.*)"] :> "Combinatorica`" <> "$1"}]} &
Of course, this is working at a very low level, so take care.