2011-08-10 3 views
0

다음은 F #의 예상치 못한 (나에 의한) 동작입니다. 나는 순서 정렬 간단한 클래스가 다음 Seq.sort 정렬 순서를 수행F # Seq.sort가 입력 시퀀스의 복사본을 반환합니까?

private class TestObject : IComparable 
    { 
     public TestObject(double Value) 
     { 
      this.Value = Value; 
     } 

     public void Update(double NewValue) 
     { 
      this.Value = NewValue; 
     } 

     public double Value { get ; private set; } 

     public int CompareTo(object Comparable) 
     { 
      return this.Value.CompareTo((Comparable as TestObject).Value); 
     } 

     public override string ToString() 
     { 
      return Value.ToString(); 
     } 
    } 

    [Test] 
    public void TestUpdate_OK() 
    { 

     var nums = new double[]{7,4,3,12,11,3,8}; 

     var values = nums.Select(n => new TestObject(n)).ToArray(); 

     var q = new MyQueue<TestObject>(values); 

     Console.WriteLine (q.ToString()); 

     // update one of the values in the collection - should not re-sort the collection 
     values[3].Update(2.0); 

     Console.WriteLine (q.ToString()); 

     Assert.AreEqual(q.First.Value, 3.0); 
    } 

, 그리고 : 나는 (C#으로) 약간 인위적인 단위 테스트를 작성했습니다

type MyQueue<'a when 'a : comparison> (values : 'a[]) = 

    let vals = 
     Seq.sort values 

    member this.First = Seq.nth 0 vals 

    override this.ToString() = 
     Seq.fold (fun s a -> s + a.ToString() + ";") "" vals 

을 테스트하려면 첫 번째 출력은 올바른 것입니다 :

3; 3; 4; 7; 8; 11; 12;

그러나, 테스트를 갱신 (참조 타입) 오브젝트는 순서 재정렬되게 :

2, 3, 3, 4, 7; 8; 11;

나는 참조 개체의 값이 변경 이후 MyQueue 인 객체의 발스 지금, 분류되지 않은 것이라고 예상하지만, Seq.sort 다시 수행 된 것으로 나타납니다. 나는 이해하지 못한다. 나는 함수형 프로그래밍의 목적이 부작용을 피하는 것이라고 생각했다. 왜 이런 행동을합니까?

답변

2

let vals = Seq.sort values은 vals 변수를 소비 할 때까지 실제로 값을 정렬하지 않습니다. 즉, Seq.fold가 toString 메소드에서 수행하는 작업, 즉 vals 시퀀스를 소비하고 그 시점에서 정렬이 발생합니다. 값은 그 시점에 values ​​배열에 있으며, 그 값은 정렬되므로 기본적으로 정렬은 toString 메서드를 호출 할 때 발생합니다.

또한 FP라고 부르지 않을 것입니다. 기본적으로 개인 상태로 유형을 생성하여 OOP를 수행하고 그 상태가 유형 멤버에 의해 액세스되므로

문제는 시퀀스가 ​​작동하는 방식과 관련이 있으며 일반적으로 FP에 적용 할 수 없습니다.

+0

이것이 내가 이해하지 못하는 것의 핵심이라고 생각합니다. 내 단위 테스트에는 2 개의 ToString()이 있습니다. 나는 그 종류가 처음에 일어날 것으로 예상했을 것이다. 따라서 첫 번째 ToString()은 예상대로 정렬됩니다. 그러나 두 번째 출력도 다시 정렬되며 어디에서 오는 것인지 이해할 수 없습니다. – Aidan

+0

그리고 그것은 FP가 아니라는 것에 동의하지만, F #을 순수하게 기능화하기 위해 expcet하지 않습니다. 그러나 나는 그 명령문이 vals = Seq.sort 값을 기능적으로 동작하도록 할 것을 기대했다. – Aidan

+0

ToString을 호출 할 때 정렬이 일어나기 때문에 ToString을 호출 할 때마다 기본 배열이 정렬되고이 정렬 된 배열의 문자열 표현이 반환된다. 경우에 u는 'let vals = Array'를 만든다.정렬 값 '이면 정렬은 객체가 만들어 질 때만 발생하며 toString은 Array.sort가 새로운 정렬 된 배열을 만들 때 원래 배열 객체의 수정과 관계없이 항상 동일한 결과를 반환합니다. – Ankur

1

F # Seq.sort는 입력 시퀀스의 복사본을 반환합니까?

예. 그 밖에 할 수있는 것 - 복사해야하는 일련의 값 유형의 순서를 변경하는 것입니다 (모든 .NET 언어에서 true).

는 (이것은 C# 및 VB에서 LINQ 연산자를 포함 : 게으른 측면이 첫 번째 복사 요소가 필요할 때 사본 만 구성되어 있는지, 그리고 그 시점에서 완전히 새로운 컬렉션이 생성됩니다.)

0

당신이 할 수있는 실제로 f # here에 대한 소스 코드에서이를 직접 확인하십시오.하지만 간단히 말해서 Seq.toArray를 호출하고 배열을 정렬하고 시퀀스를 다시 배열로 반환하십시오.