F # Seq.sort возвращает копию входной последовательности? - PullRequest
0 голосов
/ 10 августа 2011

Вот неожиданное (мной) поведение в F #. У меня есть простой класс, который сортирует последовательность:

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

Я написал слегка надуманный модульный тест (в C #), чтобы проверить это:

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

Seq.sort выполняет сортировку последовательности, и первый вывод верен:

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

Однако обновление объекта теста (ссылочного типа) приводит к повторной сортировке последовательности:

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

Я ожидал, что значения в объекте MyQueue теперь будут не отсортированы, так как значение в ссылочном объекте изменилось, но Seq.sort, кажется, был выполнен снова. Я не понимаю, я думал, что целью функционального программирования было избежать побочных эффектов. Почему я получаю такое поведение?

Ответы [ 3 ]

2 голосов
/ 10 августа 2011

Причина этого в том, что оператор let vals = Seq.sort values на самом деле не сортирует значения, пока какой-то код не использует переменную vals, т.е. то, что ваш Seq.fold делает в методе toString, он использует последовательность vals, и в это время происходит сортировка и какие бы значения ни находились в массиве значений в это время, эти значения сортируются, поэтому в основном сортировка происходит в тот момент, когда вы вызываете метод toString.

Кроме того, я не буду называть это FP :), поскольку вы в основном выполняете ООП, создавая тип с закрытым состоянием, и это состояние доступно членам типа.

Ваша проблема связана с тем, как работает последовательность, и в целом не применима к FP.

1 голос
/ 10 августа 2011

F # Seq.sort возвращает копию входной последовательности?

Да. Что еще это может сделать - изменить порядок набора типов значений, которые нужно скопировать (верно для всех языков .NET).

(Это включает в себя операторы LINQ в C # и VB: ленивый аспект заключается в том, что копирование выполняется только тогда, когда требуется первый скопированный элемент, и в этот момент создается полная новая коллекция.)

0 голосов
/ 10 августа 2011

Вы можете проверить это непосредственно в исходном коде для f # здесь , но вкратце то, что он делает, вызывает Seq.toArray, сортирует массив на месте и возвращает этот массив обратно как последовательность.

...