Подтвердить что ты не робот

В чем преимущества встроенной неизменности F # над С#?

  • Я слышал, что F # имеет встроенную поддержку неизменности, но как насчет того, что нельзя реплицировать на С#? Что вы получаете от неизменяемых данных F #, которые вы не получаете из неизменяемых данных С#?

  • Также в F # нет способа создания изменяемых данных? Все ли неизменным?

  • Если вы используете как С#, так и F # в приложении, можете ли вы изменить неизменяемые данные F # на С#? Или вам просто нужно создавать новые типы С#, которые используют неизменяемые данные F # и заменяют ссылки, которые указывают на эти данные?

4b9b3361

Ответ 1

  • Способ работы F # упрощает работу с неизменяемыми данными, но в С# нет ничего особого, что невозможно сделать в С#. Однако он может не содержать четкого синтаксиса.

  • F # поддерживает изменяемые данные с ключевым словом mutable. F # не является чистым функциональным языком. Он поддерживает императивные конструкции, такие как петли, а также функциональные конструкции.

  • Нет. Неизменяемые типы действительно неизменяемы. Система типа .NET используется на обоих языках. Вы также не можете изменять неизменяемые данные из С# (если не считать отражений и хаков памяти).

Ответ 2

Мехрдад уже ответил на все ваши вопросы, но только для того, чтобы подробнее остановиться на №1 - разница в количестве кода, который вам нужно написать. Например, здесь определение и пример использования точки только для чтения в С#:

class Point
{
    private readonly int x, y;

    public int X { get { return x; } }

    public int Y { get { return y; } }

    public Point(int x, int y)
    {
        this.x = x;
        this.y = y;
    }
}

var p = new Point(1, 2);

Вы можете использовать автоматические свойства, чтобы сделать это немного короче, но тогда неизменяемость не применяется для кода внутри определения класса, только для его клиентов.

В F # вы просто напишите:

type Point = { x: int; y: int }
let p = { x = 1; y = 2 }

И если вы хотите, чтобы он изменялся:

type Point = { mutable x: int; mutable y: int }
let p = { x = 1; y = 2 }
p.x <- 3
p.y <- 4

Ответ 3

Самая большая разница между F # и С# относительно неизменяемости заключается в том, что F # по умолчанию неизменен. Он позволяет копировать все неизменные конструкции и коллекции в С#, но для дополнительной работы требуется много. В F # вы просто получите его бесплатно.

F # - это гибридный язык и поддерживает модификацию в нескольких формах. Самый простой в ключевом слове mutable

let value1 = 42; // immutable
let mutable value2 = value1; // mutable
value2 <- 13;  

Запрет трюков отражения, как только данные создаются в F #, он неизменен независимо от языка, из которого вы его потребляете.

Ответ 4

Как отмечают другие, существуют некоторые важные преимущества использования неизменяемых данных. Чтобы назвать несколько:

  • Параллелизация. Легче распараллелить программу, которая вычисляет результат и возвращает его в неизменной структуре данных.
  • Понимание кода. Если вы пишете программу с использованием неизменяемых данных, единственное, что может сделать кусок кода - это вернуть результат - это делает программу более читаемой, потому что вы видите, что функция/метод делает только путем анализа входов и выходов

Технически вы можете написать ту же неизменяемую структуру данных как в С#, так и в F #. Проблема в том, что F # побуждает вас это делать, а запись истинных неизменяемых данных в С# немного больно. Это означает, что при написании кода F # вы, скорее всего, будете писать неизменяемые структуры (потому что это проще!), И вы будете использовать изменчивость (что возможно и в F #), только когда вам это действительно понадобится (это сложнее!)

Помимо объявления неизменяемых типов по умолчанию, F # также имеет некоторые приятные функции, которые облегчают работу с ними. Например, при работе с записями:

type MyRect = { X : int; Y : int; Width : int; Height : int }
let r = { X = 0; Y = 0; Width = 200; Height = 100 }

// You'll often need to create clone with one field changed:
let rMoved1 = { X = 123; Y = r.Y; Width = r.Width; Height = r.Height }

// The same thing can be written using 'with' keyword:
let rMoved2 = { r with  X = 123 }

Вы тоже можете написать то же самое в С#, но вам нужно объявить неизменяемую структуру данных с помощью метода WithX, который возвращает клон с измененным полем X, WithY, WithWidth и т.д. Здесь приведен неполный пример:

class MyRect {
  readonly int x, y, width, height;

  MyRect WithX(int newX) {
    return new MyRect(newX, y, width, height);
  }
  // etc...
}

Это много работы без какой-либо помощи компилятора.

Ответ 5

Я думаю, что вы смотрите на это из слишком детализированной точки зрения для функции.

Я бы увидел главное преимущество неизменности, по умолчанию функциональных программистов, чтобы быть в зависимости от того, как это влияет на фактический набор умений программирования разработчика. Когда мутация является по умолчанию, набор умений программирования ориентирован на решения путем изменения данных. Когда неизменяемость по умолчанию, набор умений программирования ориентирован на решения путем преобразования данных.

Выяснить, почему последний разум настроен лучше. При разработке программ посредством мутации данных вы в конечном итоге увязли в мельчайших подробностях, поэтому ваш фокус, как правило, зависит от того, как программа работает "в малом". При разработке программ путем преобразования данных вам не нужно беспокоиться о многих тонких деталях (например, как разные мутирующие части вашей программы взаимодействуют друг с другом), и ваш фокус, как правило, зависит от того, как работает программа большой ". Таким образом, последний набор умений побуждает разработчика к получению более четкой и четкой картины о том, как работает программа.

В то время как хорошая чистая "большая картина" программы хороша, в некоторых случаях проблемы с реальной жизнью могут перевесить ее. Некоторые структуры данных (массивы, многомерные массивы) не являются хорошими кандидатами на неизменность из-за высокой стоимости создания новых копий, поэтому необходимо всегда применять здравый смысл, когда нельзя использовать неизменность даже с функциональными языками.

Изменить ответ на комментарий:

Пуристы функционального языка утверждают, что это сделает код более уродливым. Я считаю себя не пуристом, поэтому я так не думаю; ну, возможно, уродливее с теоретической точки зрения.

F # - нечистый функциональный язык программирования, поэтому он поддерживает изменчивость, когда это необходимо. Если часть вашего состояния будет изменчивой, это не приведет к недействительности преимуществ того, чтобы большая часть вашего состояния была неизменной.

В большинстве случаев вы в конечном итоге используете другую (чистую) структуру данных, в которой вы обычно используете массив на императивном языке. Например. кортеж, список или дерево (или сборка/построение карты поверх дерева, стандартные библиотеки обычно поставляются с реализацией с хорошей временной сложностью).

И если вы считаете, что вам действительно нужен измененный массив (по соображениям производительности), у вас есть его, поэтому ничто не мешает вам использовать его.

Ответ 6

Что вы получаете от неизменяемого F # данные, которые вы не получаете от С# неизменяемые данные?

F # позволяет вам легко создавать измененные копии неизменяемых данных, это очень утомительно и требует много времени от С#. Подумайте о создании записи в F #:

type Person = { FirstName: string; MiddleName: string; LastName: string }
let me = { FirstName = "Robert"; MiddleName = "Frederick"; LastName = "Pickering" }

Скажем, мне нужно изменить поле последнего имени, в F # я могу сделать это, сделав копию, используя ключевое слово "с":

let me' = { me with LastName = "Townson" }

Если вы хотите сделать это на С#, вам нужно будет создавать методы, которые копировали каждое поле в новую структуру и там была бы сильная возможность, что вы могли бы смешать поля.

Существуют и другие подходящие преимущества для коллекций. Например, С# поддерживает неизменяемый ReadOnlyCollection. Однако каждый раз, когда вы хотите добавить новый элемент в эту коллекцию, вы должны сделать копию всех коллекций. F # build in list позволяет вам просто добавить новый элемент в конец списка без его копии, т.е. Недавно полученный список фактически поделится большей частью старого списка. то есть:.

let myList = [3; 2; 1]
let myList' =  4 :: myList

При создании "myList" весь "myList" сохраняется без изменений, а "4" добавляется к нему, чтобы создать "myList" .

Ответ 7

Что вы получаете от неизменяемых данных F #, которые вы не получаете из неизменяемых данных С#?

Первое преимущество заключается в том, что функция F # не имеет никакого другого эффекта, кроме возвращения его результата. Глобальные данные не изменяются, на изменчивые данные не зависят, и поэтому вам гарантировано, что при условии, что вы будете хранить неизменяемые данные, один и тот же вызов производит одинаковый результат, надежно, каждый раз.

Это первое преимущество уже само по себе, потому что это упрощает понимание кода, но большая выгода выигрывает, потому что функции F # могут быть легко составлены. Программирование по композиции функций оказывается невероятно мощным, модульным способом программирования с использованием многоразовых частей. И вы можете создавать действительно мощные части, которые могут быть объединены множеством разных способов, поэтому вы можете писать больше программ с меньшим количеством кода.

Эти идеи объясняются лучше, чем я когда-либо мог в знаменитой бумаге Джона Хьюза Почему вопросы функционального программирования. Джон объясняет, как удаление способности мутировать фактически добавляет выразительную силу к языку над всеми. Прочтите статью!