문제

나는 서핑을 했다 이것 며칠 전 "C#의 익명 재귀" 사이트에 대해 알아봤습니다.이 기사의 요점은 다음 코드가 C#에서 작동하지 않는다는 것입니다.

Func<int, int> fib = n => n > 1 ? fib(n - 1) + fib(n - 2) : n;

그런 다음 기사에서는 사용 방법에 대해 자세히 설명합니다. 카레 그리고 Y-조합기 C#의 "익명 재귀"로 돌아갑니다.이것은 꽤 흥미롭지만 일상적인 코딩에는 다소 복잡할 것 같습니다.이 시점에서는 적어도...

저는 직접 보는 걸 좋아해서 모노를 열었어요 CSharp REPL 그리고 그 줄을 입력했습니다.오류가 없습니다.그래서 나는 들어갔다. fib(8);.놀랍게도 효과가 있었습니다!REPL은 다음과 같이 응답했습니다. 21!

나는 이것이 REPL의 마법일지도 모른다고 생각하여 'vi'를 실행하고 다음 프로그램을 입력하고 컴파일했습니다.

using System;

public class Program
{
    public static void Main(string[] args)
    {
        int x = int.Parse(args[0]);
        Func<int, int> fib = n => n > 1 ? fib(n - 1) + fib(n - 2) : n;
        Console.WriteLine(fib(x));
    }
}

완벽하게 구축되고 실행되었습니다!

저는 Mac에서 Mono 2.10을 실행하고 있습니다.지금은 Windows 시스템에 액세스할 수 없으므로 Windows의 .NET에서 테스트할 수 없습니다.

이 문제는 .NET에서도 수정되었습니까? 아니면 Mono의 자동 기능입니까?이 기사는 몇 년 전의 것입니다.

Mono만이라면 다음 면접에서 내가 선택한 언어(Mono C#)로 Fibinocci 함수를 작성하라는 요청을 받고 .NET이 작동하지 않는다는 경고를 제공해야 합니다.글쎄요, 사실 저는 제 일을 사랑하기 때문에 기다릴 수 있어요.그래도 흥미롭다...

업데이트:

Mono는 실제로 "익명" 재귀를 수행하지 않습니다. fib 지명된 대리인으로.내 잘못이야.Mono C# 컴파일러가 null 가치 fib 할당 전에는 아래에 언급된 버그가 있습니다..NET C# 컴파일러가 코드를 컴파일하지 않더라도 .NET CLR은 결과 어셈블리를 제대로 실행하기 때문에 "컴파일러"라고 말합니다.

모든 나치 인터뷰에 대해:

Func<int, int> fib = n => n > 1 ? fib(n - 1) + fib(n - 2) : n;

반복 버전으로 대체될 수 있습니다.

Func<int, int> fib = n => 
{
    int old = 1;
    int current = 1;
    int next;

    for (int i = 2; i < n; i++)
    {
        next = current + old;
        old = current;
        current = next;
    }
    return current;
};

C#과 같은 언어에서는 재귀 버전이 비효율적이므로 이 작업을 수행할 수 있습니다.어떤 사람들은 다음을 사용하는 것을 제안할 수도 있습니다. 메모이제이션 그러나 이는 반복 방법보다 여전히 느리기 때문에 단순히 멍청한 것일 수도 있습니다.:-)

하지만 이 시점에서 이것은 다른 어떤 것보다 함수형 프로그래밍에 대한 광고에 가깝습니다(재귀 버전이 훨씬 더 좋기 때문입니다).내 원래 질문과는 전혀 관련이 없지만 일부 답변은 그것이 중요하다고 생각했습니다.

도움이 되었습니까?

해결책

이것은 벌레 모노 컴파일러에서.이는 §12.3.3 섹션을 위반합니다. 사양.변수 악의 없는 거짓말 명확하게 할당되지 않았기 때문에 변수 초기화 프로그램에서 사용할 수 없습니다.

다른 팁

위의 설명에서 언급했듯이 Mono가 그렇게 하면 버그가 있는 것입니다.스펙에는 이것이 오류로 감지되어야 한다고 명시되어 있습니다.물론 버그는 대부분 무해하며 대부분의 경우 원하는 대로 작동합니다.우리는 이러한 종류의 재귀를 합법화하기 위해 규칙을 변경하는 것을 고려했습니다.기본적으로 우리는 이 좁게 정의된 사례가 합법적이라는 특별한 사례를 사양에 추가해야 합니다.하지만 결코 우선순위가 높지 않았습니다.

이 문제에 대한 더 많은 생각을 보려면 해당 주제에 대한 내 기사를 참조하십시오.

http://blogs.msdn.com/b/ericlippert/archive/2006/08/18/706398.aspx

그런데 저는 인터뷰에서 fib를 직접 재귀적으로 구현한 사람을 고용하지 않을 것입니다.그것은 극도로 무능한;실행 시간은 출력 크기에 비례하며 fib는 기하급수적으로 증가합니다.재귀를 효율적으로 사용하려면 메모와 함께, 또는 명백한 반복 솔루션을 구현하십시오.

이 시도...

Func<int, int> fib = null;
fib = n => n > 1 ? fib(n - 1) + fib(n - 2) : n; 

...문제는 위의 방법으로 fib를 사용하려고 할 때 fib가 정의되어 있지 않아 정적 분석기가 컴파일러 오류를 보고한다는 것입니다.

흥분해서 나는 근본적으로 착각 한 것 같습니다..NET이나 Mono는 원본 기사에서 의미하는 방식으로 "익명 재귀"를 제공하지 않습니다.넌 그냥 지나갈 수 없었어 fib 독립된 실체로서.

Mono C# REPL에서 다음 시퀀스를 확인하세요.

csharp> Func<int, int> fib = n => n > 1 ? fib(n - 1) + fib(n - 2) : n; 
csharp> fibCopy = fib;
csharp> fib(6);
8
csharp> fibCopy(6);
8
csharp> fib = n => n * 2;
csharp> fib(6);
12
csharp> fibCopy(6);
18

이 때문입니다:

fib = n => n * 2;
fibCopy = n > 1 ? fib(n - 1) + fib(n - 2) : n;

다시 말해서,

fibCopy = n > 1 ? (n - 1) * 2 + (n - 2) * 2 : n;    // at the moment

분명히, fibCopy 단지 현재의 정의를 가리키고 있을 뿐입니다. fib (대리자) 자체가 아닙니다.따라서 Mono는 실제로 null 에게 fib 초기 할당 중에 할당이 유효하도록 합니다.

나는 선언하지 않아도 되는 편리함을 훨씬 선호한다. null 그래서 나는 이 행동을 좋아한다.그럼에도 불구하고 원본 기사에서 실제로 이야기하고 있는 내용은 아닙니다.

Microsoft의 C# 컴파일러에서는 먼저 설정한 경우에만 작동합니다. fib 에게 null.

그렇지 않으면 오류가 발생합니다. fib 할당되기 전에 사용됩니다.
Mono의 컴파일러는 이 오류를 피할 만큼 "똑똑"합니다(즉, 공식 사양을 위반합니다).

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top