首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >函数/宏,如果其中一个参数包含对自身的调用,则返回true。

函数/宏,如果其中一个参数包含对自身的调用,则返回true。
EN

Code Golf用户
提问于 2014-06-23 01:05:06
回答 12查看 2.3K关注 0票数 7

编写一个函数(或宏),该函数返回true当且仅当其参数中至少有一个参数包含对函数本身的调用,否则为false。

例如:

代码语言:javascript
复制
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,其中不带参数的函数仍然可以用参数调用。

EN

回答 12

Code Golf用户

发布于 2015-02-24 19:17:32

Mathematica...

...was是为此而做的。

代码语言:javascript
复制
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计算函数参数,这样我们就可以分析函数中的表达式树。HoldHoldAll是干什么用的。Mathematica本身就将它应用到各地,为某些实现提供特例。例如,如果您调用Length[Permutations[list]],它将永远不会真正创建所有这些排列并浪费大量内存,而是认识到它可以简单地将其计算为Length[list]!

让我们以最后一个调用f[True || f[1]]为例,详细查看上面的代码。通常,Mathematica将首先计算函数参数,因此这将简单地短路并调用f[True].但是我们已经确定

代码语言:javascript
复制
SetAttributes[f, HoldAll]

这指示Mathematica不要计算参数,因此调用的FullForm (即内部表达式树,没有任何语法糖)是

代码语言:javascript
复制
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]]

这就是它真正的全部。

票数 11
EN

Code Golf用户

发布于 2015-02-25 16:24:28

C++11

与表达式模板类似,我们可以传播这样一个事实:我们在函数参数列表中调用了函数的返回类型。

首先,我们需要一些助手类和函数:

代码语言:javascript
复制
#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!

现在,我们可以将它用于与问题中完全相同的代码:

代码语言:javascript
复制
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";
}

同上的产出:

代码语言:javascript
复制
0//a==false
0//b==false
1//c==true
1//d==true (weakly-typed language)
1//e==true (strongly-typed language)
票数 6
EN

Code Golf用户

发布于 2014-06-23 10:17:44

C

代码语言:javascript
复制
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中):

代码语言:javascript
复制
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。

票数 4
EN
页面原文内容由Code Golf提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codegolf.stackexchange.com/questions/32250

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档