编写一个函数(或宏),该函数返回true当且仅当其参数中至少有一个参数包含对函数本身的调用,否则为false。
例如:
int a=function(); //a==false
int b=function(0); //b==false
int c=function(function(0)); //c==true
int d=function(3*function(1)+2); //d==true (weakly-typed language)
bool e=function(true||function(1)); //e==true (strongly-typed language) 编辑:函数/宏可以调用其他辅助函数/宏。
编辑2:函数必须至少使用一个参数,除非所使用的语言行为像C,其中不带参数的函数仍然可以用参数调用。
发布于 2015-02-24 19:17:32
...was是为此而做的。
SetAttributes[f, HoldAll]
f[x___] := ! FreeQ[Hold@x, _f]
f[] (* False *)
f[0] (* False *)
f[f[0]] (* True *)
f[3 f[1] + 2] (* True *)
f[True || f[1]] (* True *)一切都是一个表达式,一个表达式有一个头和一些元素。所以1+2实际上是Plus[1,2],{1,2}实际上是List[1,2]。这意味着我们可以匹配我们感兴趣的头部的任何表达式-在本例中是函数f本身。
我们所需要做的就是找出一种方法,在调用函数之前,防止Mathematica计算函数参数,这样我们就可以分析函数中的表达式树。Hold和HoldAll是干什么用的。Mathematica本身就将它应用到各地,为某些实现提供特例。例如,如果您调用Length[Permutations[list]],它将永远不会真正创建所有这些排列并浪费大量内存,而是认识到它可以简单地将其计算为Length[list]!。
让我们以最后一个调用f[True || f[1]]为例,详细查看上面的代码。通常,Mathematica将首先计算函数参数,因此这将简单地短路并调用f[True].但是我们已经确定
SetAttributes[f, HoldAll]这指示Mathematica不要计算参数,因此调用的FullForm (即内部表达式树,没有任何语法糖)是
f[Or[True,f[1]]]这个论点将被f以这种形式接收到。下一个问题是,在f中,当我们使用这个参数时,Mathematica将再次尝试评估它。我们可以用Hold@x (用于Hold[x]的语法糖)来抑制这一点。此时,我们已经得到了原始表达式树的句柄,并对其进行了我们想要的任何操作。
要在表达式树中查找模式,我们可以使用FreeQ。它检查表达式树中没有找到给定的模式。我们使用模式_f,它将任何子表达式与head f匹配(这正是我们要寻找的)。当然,FreeQ返回与我们想要的相反的结果,所以我们否定了结果。
还有一个微妙之处:我已经将参数指定为x___,它是由0或多个元素组成的序列。这确保了f与任意数量的参数一起工作。在第一个调用中,f[] --这意味着Hold@x将简单地变成Hold[]。如果有多个参数,比如f[0,f[1]],那么Hold@x就是Hold[0,f[1]]。
这就是它真正的全部。
发布于 2015-02-25 16:24:28
与表达式模板类似,我们可以传播这样一个事实:我们在函数参数列表中调用了函数的返回类型。
首先,我们需要一些助手类和函数:
#include <iostream>
template <bool FunctionWasInParameters> struct FunctionMarker {
operator bool() const { return FunctionWasInParameters; }
operator int() const { return FunctionWasInParameters; }
};
template <bool... values> struct Or;
template <bool first, bool... values> struct Or<first, values...> {
static constexpr bool value = first || Or<values...>::value;
};
template <> struct Or<> { static constexpr bool value = false; };
template <class T> struct is_FunctionMarker {
static constexpr bool value = false;
};
template <bool B> struct is_FunctionMarker<FunctionMarker<B>> {
static constexpr bool value = true;
};
#define OVERLOAD_OPERATOR_FOR_FUNCTION_MARKER(OPERATOR) \
template <bool B, class T> \
FunctionMarker<B> operator OPERATOR(FunctionMarker<B>, T) { \
return {}; \
} \
template <bool B, class T> \
FunctionMarker<B> operator OPERATOR(T, FunctionMarker<B>) { \
return {}; \
} \
/* to break ambiguity by specialization */ \
template <bool B, bool B2> \
FunctionMarker<B || B2> operator OPERATOR(FunctionMarker<B>, \
FunctionMarker<B2>) { \
return {}; \
}
OVERLOAD_OPERATOR_FOR_FUNCTION_MARKER(|| )
OVERLOAD_OPERATOR_FOR_FUNCTION_MARKER(+)
OVERLOAD_OPERATOR_FOR_FUNCTION_MARKER(*)
// TODO: overload all other operators!现在,我们可以将它用于与问题中完全相同的代码:
template <class... Args>
auto function(Args... args)
-> FunctionMarker<Or<is_FunctionMarker<Args>::value...>::value> {
return {};
}
FunctionMarker<false> function() { return {}; }
int main() {
int a = function();
int b = function(0);
int c = function(function(0));
int d = function(3 * function(1) + 2);
bool e = function(true || function(1));
// clang-format off
std::cout << a << "//a==false\n"
<< b << "//b==false\n"
<< c << "//c==true\n"
<< d << "//d==true (weakly-typed language)\n"
<< e << "//e==true (strongly-typed language)\n";
}同上的产出:
0//a==false
0//b==false
1//c==true
1//d==true (weakly-typed language)
1//e==true (strongly-typed language)发布于 2014-06-23 10:17:44
public PcgBool f(params object[] args)
{
return args.Any(p => p is PcgBool);
}
public class PcgBool
{
public PcgBool() { }
public PcgBool(bool value)
{
Value = value;
}
private bool Value;
public static implicit operator bool(PcgBool pcgBool)
{
return pcgBool.Value;
}
public static implicit operator PcgBool(bool value)
{
return new PcgBool(value);
}
}用法(在LINQPad中):
void Main()
{
Console.WriteLine(f(1,2,f(3),4)); // True
Console.WriteLine(f(1,2,3,"4")); // False
}这里的诀窍是通过传递一个类似布尔值的自定义类型(PcgBool)来使f更清楚地知道参数。
我希望把一种潜移默化的自定义类型返回到bool中,不会被认为是欺骗。从技术上讲,您可以使用返回值,就好像它是bool类型的一样,并且要求“返回true当且仅当”等问题,但是从来没有声明返回类型必须是bool。
https://codegolf.stackexchange.com/questions/32250
复制相似问题