Hàm / macro trả về true nếu một trong các đối số của nó chứa lệnh gọi chính nó


7

Viết một hàm (hoặc macro) trả về true khi và chỉ khi ít nhất một trong các đối số của nó chứa lệnh gọi đến chính hàm đó và sai khác .

Ví dụ:

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) 

EDIT: Hàm / macro có thể gọi các hàm / macro phụ trợ khác.

EDIT 2: Hàm phải có ít nhất một đối số, trừ khi ngôn ngữ được sử dụng hành xử như C, trong đó một hàm không có đối số vẫn có thể được gọi bằng các đối số.


Liệu nó có phải hoạt động trong một bối cảnh như thế không print(func(), func(func())), hay sẽ chỉ có một cuộc gọi cấp cao nhất đến chức năng ngay sau khi nó được xác định?
thuật toán

Nó nên hoạt động trong tình huống đó.

10
Tại sao lại chấp nhận nhanh như vậy?
Kyle Kanos

1
Tôi không thích câu hỏi này vì nó chỉ có thể giải được bằng các ngôn ngữ cho phép bạn kiểm tra cây biểu thức khi chạy.
FUZxxl 24/2/2015

1
@FUZxxl: Tôi không đồng ý; Tôi vừa đăng một câu trả lời hoạt động tốt ngay cả khi các cuộc gọi gián tiếp thông qua FFI (và do đó không thể xem cây biểu thức của các chức năng bên trong).

Câu trả lời:


11

Toán học ...

... Đã được thực hiện cho điều này.

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 *)

Mọi thứ đều là một biểu thức và một biểu thức có Head và một số phần tử. Vì vậy, 1+2thực sự là Plus[1,2], và {1,2}thực sự là List[1,2]. Điều này có nghĩa là chúng ta có thể khớp bất kỳ biểu thức nào cho phần đầu mà chúng ta quan tâm - trong trường hợp này là fchính hàm đó.

Tất cả những gì chúng ta cần làm là tìm cách ngăn Mathicala đánh giá các đối số hàm trước khi hàm được gọi, sao cho chúng ta có thể phân tích cây biểu thức trong hàm. Những gì HoldHoldAlllà cho. Mathicala tự sử dụng điều này cho tất cả mọi nơi để cung cấp các trường hợp đặc biệt cho việc triển khai nhất định. Ví dụ, nếu bạn gọi Length[Permutations[list]]nó sẽ không bao giờ thực sự tạo ra tất cả những hoán vị và lãng phí bộ nhớ, mà thay vào đó nhận ra rằng nó chỉ đơn giản có thể tính toán điều này như Length[list]!.

Chúng ta hãy xem chi tiết mã ở trên, sử dụng cuộc gọi cuối cùng f[True || f[1]]làm ví dụ. Thông thường, Mathicala sẽ đánh giá các đối số hàm trước, vì vậy điều này chỉ đơn giản là ngắn mạch và gọi f[True]. Tuy nhiên chúng tôi đã thiết lập

SetAttributes[f, HoldAll]

Điều này hướng dẫn Mathicala không đánh giá các đối số, do đó, FullFormlệnh gọi (tức là cây biểu thức bên trong, không có bất kỳ đường cú pháp nào)

f[Or[True,f[1]]]

Và đối số sẽ thực sự được nhận bằng fhình thức này. Vấn đề tiếp theo là, bên trong f, ngay khi chúng ta sử dụng đối số, Mathematica sẽ lại cố gắng đánh giá nó. Chúng ta có thể ngăn chặn điều này cục bộ bằng Hold@x(đường cú pháp cho Hold[x]). Tại thời điểm này, chúng tôi đã xử lý cây biểu thức ban đầu và làm với nó bất cứ điều gì chúng tôi muốn.

Để tìm một mẫu trong cây biểu thức chúng ta có thể sử dụng FreeQ. Nó kiểm tra rằng một mẫu nhất định không được tìm thấy trong cây biểu thức. Chúng tôi sử dụng patter _f, phù hợp với bất kỳ biểu hiện phụ nào với đầu f(chính xác là những gì chúng tôi đang tìm kiếm). Tất nhiên, FreeQtrả về ngược lại với những gì chúng ta muốn, vì vậy chúng tôi phủ nhận kết quả.

Thêm một sự tinh tế nữa: Tôi đã chỉ định đối số là x___, đó là một chuỗi gồm 0 hoặc nhiều phần tử. Điều này đảm bảo rằng fhoạt động với bất kỳ số lượng đối số. Trong cuộc gọi đầu tiên, f[]điều này có nghĩa là Hold@xsẽ đơn giản trở thành Hold[]. Nếu có nhiều đối số, như thế f[0,f[1]], thì Hold@xsẽ là Hold[0,f[1]].

Đó thực sự là tất cả để có nó.


6

C ++ 11

Tương tự như các mẫu biểu thức, chúng ta có thể truyền bá thực tế rằng chúng ta đã gọi hàm bên trong một danh sách tham số hàm trong kiểu trả về của nó.

Đầu tiên chúng ta cần một số lớp và hàm trợ giúp:

#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!

Bây giờ, chúng ta có thể sử dụng nó cho cùng một mã chính xác như trong câu hỏi:

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";
}

Đầu ra từ ideone:

0//a==false
0//b==false
1//c==true
1//d==true (weakly-typed language)
1//e==true (strongly-typed language)

4

C #

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);
    }
}

Cách sử dụng (trong LINQPad ):

void Main()
{
    Console.WriteLine(f(1,2,f(3),4)); // True
    Console.WriteLine(f(1,2,3,"4")); // False
}

Mẹo ở đây là fnhận thức rõ hơn về các tham số, bằng cách chuyển một loại tùy chỉnh ( PcgBool) giống như kiểu boolean.

PS Tôi hy vọng trả lại một loại tùy chỉnh mà hoàn toàn có thể đúc từ và đến một bool không được coi là gian lận. Về mặt kỹ thuật, bạn có thể sử dụng giá trị trả về như thể nó thuộc loại bool và câu hỏi được yêu cầu "trả về true nếu và chỉ khi", v.v., nhưng không bao giờ nói loại trả về phải là bool.


Thế còn f(new PcgBool())?
Qwertiy

Hmm ... Bạn nói đúng về điều đó. Có vẻ như nó phanh câu trả lời của tôi. Thật không may, bây giờ tôi quá lười để sửa nó (đã lâu rồi ...)
Jacob

3

Lua

local x
local function f()
    local y = x
    x = true
    return y
end
debug.sethook(function()
        if debug.getinfo(2).func ~= f then
            x = false
        end
    end, "l")
print(f())
print(f(0))
print(f(f()))
print(f(f(0)))
print(f("derp" .. tostring(f())))

Và tôi đã nghĩ đến một cách để so sánh các bảng đệ quy. Làm tốt lắm, tôi không nghĩ gỡ lỗi có thể mạnh đến thế!
yyny

3

C ++ 11 TMP

Cái này dài hơn một chút. Do một số hạn chế trong các mẫu C ++, tôi đã phải làm mọi thứ với các kiểu. Do đó "True" cũng như các số được biến thành bool và int. Ngoài ra Các hoạt động +, - và || đã được chuyển thành add, mul và or_.

Tôi hy vọng điều này vẫn đủ điều kiện là một câu trả lời hợp lệ.

template <typename... Args>
struct foo;

template <>
struct foo<>
{
    static bool const value = false;
};

template <typename T>
struct is_foo
{
    static bool const value = false;
};

template <typename... Args>
struct is_foo<foo<Args...>>
{
    static bool const value = true;
};

template <typename T>
struct is_given_foo
{
    static bool const value = false;
};

template <template <typename...> class T, typename... Args>
struct is_given_foo<T<Args...>>
{
    static bool const value = foo<Args...>::value;
};

template <typename Head, typename... Tail>
struct foo<Head, Tail...>
{
    static bool const value = is_foo<Head>::value || is_given_foo<Head>::value || foo<Tail...>::value;
};

template <typename... Args>
struct add {};

template <typename... Args>
struct mul {};

template <typename... Args>
struct or_ {};

static_assert(foo<>::value == false, "int a=function(); //a==false");
static_assert(foo<int>::value == false, "int b=function(0); //b==false");
static_assert(foo<foo<int>>::value == true, "int c=function(function(0)); //c==true");
static_assert(foo<add<mul<int, foo<int>>, int>>::value == true, "int d=function(3*function(1)+2); //d==true (weakly-typed language)");
static_assert(foo<or_<bool,foo<int>>>::value == true, "bool e=function(true||function(1)); //e==true (strongly-typed language)");

// just for the sake of C++
int main()
{
    return 0;
}

Thực sự tốt đẹp! Quy tắc nào khiến định nghĩa thứ hai is_given_foođược ưa thích hơn định nghĩa thứ nhất?
frageum

Có lẽ ai đó có thể giúp tôi, vì tôi không thể tìm đúng nơi trong tiêu chuẩn để trích dẫn. Dù sao, is_given_foo thứ hai là một chuyên môn mẫu của mẫu thứ nhất, nó luôn được ưu tiên khi (các) tham số mẫu khớp với mẫu đã cho, trong trường hợp đó khi tham số là chính mẫu.
Felix Bytow

2

C

Tôi không nghĩ rằng nó có thể được thực hiện bằng các thủ tục, nhưng chúng ta luôn có thể (ab) sử dụng macro.

#include <stdio.h>
#define f(x) ((max_depth = ++depth), (x), (depth-- < max_depth))

int depth = 0;
int max_depth = 0;

char* bool(int x) { // Helper - not necessary for solution
  return x ? "true" : "false";
}

int main() {
  printf("f(1): %s\n", bool(f(1)));
  printf("f(f(1)): %s\n", bool(f(f(1))));
  printf("f(bool(f(1))): %s\n", bool(f(bool(f(1)))));
  printf("f(printf(\"f(1): %%s\\n\", bool(f(1)))): %s\n", bool(printf("f(1): %s\n", bool(f(1)))));
}

Kết quả này:

f(1): false
f(f(1)): true
f(bool(f(1))): true
f(1): false
f(printf("f(1): %s\n", bool(f(1)))): true

Macro của chúng tôi ftheo dõi độ sâu hiện tại và độ sâu tối đa đạt được kể từ khi nó được gọi. Nếu cái sau lớn hơn cái trước, thì nó đã được gọi là đệ quy.


Heh. Chúng tôi đã kết thúc với ít nhiều cùng một giải pháp cùng một lúc hoặc ít hơn.
Nghệ thuật

@Art LOL. Ngoài ra, bây giờ tôi cảm thấy rất ngớ ngẩn, vì tôi không biết về toán tử dấu phẩy (vì chữ C ở đâu đó xung quanh ngôn ngữ lựa chọn thứ 4 hoặc thứ 5 của tôi), mà tôi đã sử dụng &&và sử dụng ||. Tôi có thể cố gắng để trả lại câu trả lời của tôi.
James_pic

Chà, toán tử dấu phẩy chỉ dành cho một lớp obfuscation. Tôi sẽ không bao giờ sử dụng nó trong mã bình thường. Nhưng trong trường hợp này tôi đã bối rối khi cố gắng sử dụng các toán tử logic.
Nghệ thuật

2

C, 13

#define F(X)0

Đối số không bao giờ được mở rộng, vì vậy nó không thể gọi bất kỳ macro nào. Nó không có gì hơn một loạt các văn bản đơn giản. Như vậy, câu trả lời luôn luôn sai.


1
Đây thực sự là một câu trả lời tuyệt vời.
FUZxxl

Đã xem qua điều này trong khi nhìn vào các bài viết tiền xử lý cũ ... thực sự, điều này là sai. F(F(0))đầu tiên sẽ vui vẻ đánh giá đối số của F , F(0). Đối số đó mở rộng thành 0. Sau đó, nó đánh giá F không có sơn màu xanh trên đối số 0, dẫn đến 0. Hạn chế không đệ quy không áp dụng; đó là khi tôi có #define F(X) G#define G F(Y)đang chơi; trong này trường hợp, trong khi mở rộng F (0) đến G, và sau đó đến F (Y), token Fxuất hiện. Bởi vì tôi hiện đang mở rộng F, F có màu sơn xanh trong trường hợp này và do đó, việc mở rộng dừng lại ở F (Y).
H Walters

@HWalters Wow, bạn nói đúng. Bạn nghĩ gì về lời giải thích mới của tôi?
frageum

Vì vậy, có vẻ như bây giờ bạn đang nói rằng vì Xkhông có trong danh sách thay thế đối số, nên bất kỳ macro nào bị ràng buộc với nó đều không bao giờ được mở rộng. Nếu chúng ta giải thích rằng như là một hàm được gọi, điều đó có nghĩa là các hàm của đối số không bao giờ được gọi. Vâng, tôi nghĩ đó là chính xác.
H Walters

1

C

#include <stdio.h>

int a, b;
#define foo(x) (b=a++,(void)x,a--,!!b)

int
main(int argc, char **argv)
{
        printf("%d\n", foo(1));
        printf("%d\n", foo(0));
        printf("%d\n", foo(foo(1)));
        printf("%d\n", foo(foo(foo(1))));
        return 0;
}

Chúng ta có thể đếm độ sâu đệ quy trong macro. Sau đó chúng tôi ghi đè giá trị trả về của macro bên ngoài trong macro bên trong. !!blà để bình thường hóa giá trị trả về cho boolean. Mã được xử lý trước kết thúc như thế này:

int a, b;

int
main(int argc, char **argv)
{
 printf("%d\n", (b=a++,(void)1,a--,!!b));
 printf("%d\n", (b=a++,(void)0,a--,!!b));
 printf("%d\n", (b=a++,(void)(b=a++,(void)1,a--,!!b),a--,!!b));
 printf("%d\n", (b=a++,(void)(b=a++,(void)(b=a++,(void)1,a--,!!b),a--,!!b),a--,!!b));
 return 0;
}

Những gì về trường hợp (thừa nhận rất ngớ ngẩn) của printf("%d\n", foo(printf("%d\n", foo(1)))). Cuộc gọi bên trong footrả về 1, nhưng không gọi foo.
James_pic

1

C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BLAH(x) (strncmp( "BLAH(", #x, strlen("BLAH(")) == 0)

int main(int argc, char** argv)
{
  printf("%d\n", BLAH(1));
  printf("%d\n", BLAH("1234"));
  printf("%d\n", BLAH("BLAH"));
  printf("%d\n", BLAH(BLAHA));
  printf("%d\n", BLAH(BLAHB()));
  printf("%d\n", BLAH(BLAH));
  printf("%d\n", BLAH(BLAH()));
  printf("%d\n", BLAH(BLAH("1234")));
  return 0;
}

Macro so sánh nếu đối số của nó bắt đầu bằng "BLAH (".


1
Không hoạt động BLAH(blub(BLAH(0))).
FUZxxl

1

Algol 60

Đây là một boolean procedurecâu hỏi mà câu hỏi yêu cầu (lưu ý: Algol 60 được định nghĩa theo danh sách các mã thông báo mà không sửa cú pháp cho chúng, bên dưới sử dụng cú pháp Marst để thể hiện các mã thông báo riêng lẻ tạo nên chương trình):

boolean procedure recursion detector(n);
  boolean n;
  begin
    own boolean nested, seen nested;
    boolean was nested, retval;
    was nested := nested;
    begin if nested then seen nested := true end;
    nested := true;
    retval := n; comment "for the side effects, we ignore the result";
    nested := was nested;
    retval := seen nested;
    begin if ! nested then seen nested := false end;
    recursion detector := retval
  end;

xác minh

Đây là mã kiểm tra tôi đã sử dụng:

procedure outboolean(c, b);
  integer c;
  boolean b;
  begin
    if b then outstring(c, "true\n") else outstring(c, "false\n")
  end;

begin
  outboolean(1, recursion detector(false));
  outboolean(1, recursion detector(true));
  outboolean(1, recursion detector(recursion detector(false)));
  outboolean(1, recursion detector(false | recursion detector(true)));
  outboolean(1, recursion detector(false & recursion detector(true)));
  outboolean(1, recursion detector(recursion detector(recursion detector(false))))
end

Theo dự kiến, đầu ra là:

false
false
true
true
true             comment "because & does not short-circuit in Algol 60";
true

Giải trình

Algol 60 có thứ tự đánh giá khác với hầu hết các ngôn ngữ, có logic riêng, và thực sự mạnh mẽ và tổng quát hơn nhiều so với thứ tự đánh giá thông thường, nhưng khá khó để con người có thể hiểu được (và cũng khá khó đối với máy tính để thực hiện hiệu quả, đó là lý do tại sao nó đã được thay đổi cho Algol 68). Điều này cho phép một giải pháp không có sự gian lận (chương trình không cần nhìn vào cây phân tích hoặc bất cứ thứ gì tương tự, và không giống như hầu hết các giải pháp khác ở đây, điều này sẽ hoạt động tốt nếu cuộc gọi lồng nhau được thực hiện thông qua một FFI).

Tôi cũng quyết định thể hiện một vài điều kỳ quặc khác của ngôn ngữ. (Đáng chú ý, tên biến có thể chứa khoảng trắng; điều này khá hữu ích cho khả năng đọc, vì chúng không thể chứa dấu gạch dưới. Tôi cũng thích thực tế rằng chỉ báo nhận xét là từ theo nghĩa đen commenttrong hầu hết các mã hóa cú pháp. Algol 68 thấy điều này khá khó xử. bình luận và được giới thiệu ¢như một cách thay thế. Các trích dẫn xung quanh phần bình luận không cần thiết, tôi chỉ cần thêm chúng cho rõ ràng và để ngăn bình luận vô tình kết thúc khi tôi gõ một dấu chấm phẩy.) Tôi thực sự thích các khái niệm rộng của ngôn ngữ (nếu không phải là chi tiết), nhưng thật dài dòng đến nỗi tôi hiếm khi sử dụng nó trên PPCG.

Cách chính mà Algol 60 khác với các ngôn ngữ mà nó truyền cảm hứng (như Algol 68 và gián tiếp C, Java, v.v., những người biết K & R C có thể sẽ nhận ra cú pháp này cho các hàm) là một đối số hàm được xử lý hơi giống một chút lambda của riêng mình; ví dụ: nếu bạn đưa đối số 5cho hàm chỉ là số 5, nhưng nếu bạn đưa ra đối số đó, x+1bạn sẽ nhận được chính xác những gì bạn đã chỉ định, khái niệm " xcộng 1", thay vì kết quả của xcộng 1. Sự khác biệt ở đây là nếu xthay đổi, sau đó cố gắng đánh giá đối số chức năng trong câu hỏi sẽ thấy giá trị mới củax. Nếu một đối số hàm không được đánh giá bên trong hàm, thì nó cũng sẽ không được đánh giá bên ngoài hàm; tương tự, nếu nó được đánh giá nhiều lần trong hàm, nó sẽ được đánh giá riêng mỗi lần (giả sử rằng điều này không thể được tối ưu hóa). Điều này có nghĩa là có thể thực hiện những việc như nắm bắt chức năng của, nói ifhoặc whiletrong một chức năng.

Trong chương trình này, chúng tôi khai thác thực tế là nếu một lệnh gọi hàm xuất hiện trong một đối số cho hàm đó, điều đó có nghĩa là hàm sẽ chạy đệ quy (vì đối số được đánh giá tại điểm hoặc điểm mà hàm đánh giá chính xác , không sớm hơn hoặc muộn hơn, và điều này nhất thiết phải nằm trong cơ thể chức năng). Điều này làm giảm vấn đề phát hiện nếu chức năng đang chạy đệ quy, dễ dàng hơn nhiều; tất cả những gì bạn cần là một biến cục bộ luồng cảm nhận nếu có một cuộc gọi đệ quy (cộng với, trong trường hợp này, một cuộc gọi khác để truyền thông tin ngược lại theo cách khác). Chúng ta có thể sử dụng một biến tĩnh (nghĩa làown) cho mục đích này, vì Algol 60 là đơn luồng. Tất cả những gì chúng ta phải làm sau đó là đưa mọi thứ trở lại như cũ, để chức năng sẽ hoạt động chính xác nếu được gọi nhiều lần (theo yêu cầu của quy tắc PPCG).

Hàm không trả về giá trị mong muốn từ các cuộc gọi bên trong tại thời điểm này (ít nhất là nếu bạn cho rằng họ nên tìm kiếm các cuộc gọi tự chỉ trong các đối số của mình , thay vì tự đếm); làm cho công việc đó khá dễ dàng bằng cách sử dụng các nguyên tắc chung tương tự, nhưng phức tạp hơn và sẽ che khuất hoạt động của chức năng. Nếu điều đó được coi là cần thiết để tuân thủ câu hỏi, thì không quá khó để thay đổi.


0

Java

public class FuncOFunc{

private static int count = 0;

public static void main(String[] args){

    System.out.println("First\n" + function());
    reset();

    System.out.println("Second\n" + function(1));
    reset();

    System.out.println("Third\n" + function(function(1)));
    reset();

    System.out.println("Fourth\n" + function(3*function(1)+2));
    reset();

    System.out.println("Fifth\n" + function(function(1), function(), 4));
}

/**
 * @param args
 */
private static int function(Object...args) {
    StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
    count+=stackTraceElements.length;
    if(count>3) return 1;
    else return 0;
}

static void reset(){
    count = 0;
}
}

có thể reset()được tính là phụ trợ?

Đầu ra:

First
0
Second
0
Third
1
Fourth
1
Fifth
1

BIÊN TẬP

Đây là một phiên bản khác không sử dụng reset()phương pháp này, nhưng rất nhiều sự điên rồ. Nó tạo và biên dịch khi chạy đoạn mã trên với lệnh gọi hàm được truyền dưới dạng đối số trong stdin. Tôi muốn một giải pháp thanh lịch hơn nhưng thật đáng buồn là tôi không có quá nhiều thời gian cho việc này :(

Để chạy nó chỉ cần gọi ví dụ javac FuncOFunc.java function(function(1),function(),4).

import java.io.File;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLClassLoader;

import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

public class FuncOFunc {
    public static void main(String[] args) throws Exception {
        JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager sjfm = jc.getStandardFileManager(null, null, null);
        File jf = new File("FuncOFuncOFunc.java");
        PrintWriter pw = new PrintWriter(jf);
        pw.println("public class FuncOFuncOFunc{"
                + "public static void main(){ "
                + "     System.out.println("+ args[0] +");"
                + "}"
                + "     private static int function(Object...args)     {"
                + "         StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();"
                + "         if(stackTraceElements.length>3) return 1;"
                + "         else return 0;"
                + "     }"
                + "}");
    pw.close();
    Iterable<? extends JavaFileObject> fO = sjfm.getJavaFileObjects(jf);
    if(!jc.getTask(null,sjfm,null,null,null,fO).call()) {
        throw new Exception("compilation failed");
    }
    URL[] urls = new URL[]{new File("").toURI().toURL()};
    URLClassLoader ucl = new URLClassLoader(urls);
    Object o= ucl.loadClass("FuncOFuncOFunc").newInstance();
    o.getClass().getMethod("main").invoke(o);
    ucl.close();
}
}

Tôi không tin rằng bạn có thể buộc sử dụng để gọi reset()sau mỗi lần functiongọi. Ý tưởng của các chức năng phụ trợ là cho phép bạn gọi các phương thức riêng tư khác từ bên trong functioncơ thể ... Nhưng đó chỉ là cách giải thích của tôi về câu hỏi, hãy để người hỏi quyết định.
Jacob

Tôi có cùng cảm giác ... Chúng ta hãy chờ OP làm rõ điểm này. Trong khi đó tôi đang làm việc cho một reset()phiên bản ít hơn. Mã vẫn hoạt động ở trên nếu chỉ có một cuộc gọi trong chính (không có số lượng biến và chức năng đặt lại)
Narmer

1
Xin lỗi về sự thiếu rõ ràng, nhưng tôi có nghĩa là những gì Jacob nói bởi chức năng phụ trợ. Ngoài ra, mã đầu tiên bạn viết sẽ trả về "true" nếu bất kỳ phương thức nào, không chỉ hàm (), được gọi là hàm bên trong (...), phải không?

Chỉnh sửa của bạn phải là một số mã tồi tệ nhất tôi từng thấy. Có +1.
Cruncher

À! Cảm ơn! Đó là những gì xảy ra khi cố gắng sáng tạo mà không có sáng tạo và rất ít thời gian ... Đó có lẽ là điều tồi tệ nhất tôi từng làm trong java. Vẫn biên dịch mặc dù!
Narmer

0

Con trăn

import ast, inspect

def iscall(node, name, lineno=None):
    return isinstance(node, ast.Call) \
            and (node.lineno == lineno or lineno is None) \
            and hasattr(node.func, 'id') \
            and node.func.id == name

def find_call(node, name, lineno):
    for node in ast.walk(node):
        if iscall(node, name, lineno):
            return node

def is_call_in_args(call):
    descendants = ast.walk(call);
    name = next(descendants).func.id
    return any(map(lambda node: iscall(node, name), descendants))

def function(*args):
    this = inspect.currentframe()
    _, _, funcname, _, _ = inspect.getframeinfo(this)
    outer = inspect.getouterframes(this)[1]
    frame, filename, linenum, _, context, cindex = outer
    module = ast.parse(open(filename).read())
    call = find_call(module, funcname, linenum)
    return is_call_in_args(call)

if __name__ == '__main__':

    print("Works with these:")
    assert(function() == False)
    assert(function(3*function(1)+2) == True)
    assert(function(0) == False)
    assert(function(function(0)) == True)
    assert(function(True or function(1) == True))

    print("Does not work with multiple expressions on the same line:")
    assert(function(function()) == False); function()
    function(); assert(function(function()) == False)

Lưu nó dưới dạng selfarg.pyvà chạy nó hoặc from selfarg import functiontrong một kịch bản khác. Nó không hoạt động trong thay thế.

Sử dụng các khung ngăn xếp hiện tại và bên ngoài sẽ functioncó được tên và địa điểm cuộc gọi của nó (tệp và số dòng). Sau đó nó mở tệp thu được và phân tích nó thành một cây cú pháp trừu tượng. Nó bỏ qua lệnh gọi hàm được xác định bởi số dòng và kiểm tra xem nó có một lệnh gọi hàm khác có cùng tên trong các đối số của nó không.

chỉnh sửa : Cũng ổn với python2. Thay đổi python3 thành python trong tiêu đề.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.