Каковы преимущества встроенной неизменности F# по C#?

  1. Я слышал, что F# имеет собственную поддержку неизменности, но что относительно него, который не может копироваться в C#? Что Вы получаете неизменными данными F#, которые Вы не получаете от неизменных данных C#?

  2. Также в F#, там никакой путь не состоит в том, чтобы создать изменяемые данные? Действительно ли все неизменно?

  3. При использовании и C# и F# в приложении можно ли изменить неизменные данные F# в C#? Или необходимо ли просто создать новые типы C#, который использует неизменные данные F# и заменяет ссылки, который указывает на те данные?

25
задан Joan Venge 3 February 2010 в 18:04
поделиться

7 ответов

  1. Принцип работы F # упрощает работу с неизменяемыми данными, но в этом отношении в C # нет ничего особенного. Однако он может не обеспечивать изящного синтаксиса.

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

  3. Нет. Неизменяемые типы действительно неизменяемы. Система типов .NET является общей для обоих языков. Вы также не можете изменить неизменяемые данные из C # (конечно, за исключением рефлексии и взлома памяти).

25
ответ дан 28 November 2019 в 18:13
поделиться

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

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
17
ответ дан 28 November 2019 в 18:13
поделиться
 if (state = = ((int) RowState.Active) .ToString ())
else if (state = = ((int) RowState.NotActive) .ToString ())
Состояние 

является строковым значением записи, которое содержит значение из перечисления RowState.

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

-121--991859-

Определенно сделайте это в установщике, если вам нужно сделать это вообще.

Во-первых, установщик, вероятно, называется реже, чем приемники, поэтому вы выполняете меньше работы.

Во-вторых, вы поймете проблему раньше.

В-третьих, он обеспечивает согласованность внутреннего состояния объекта. Сохранение плохих данных означает, что вы знаете, что ваш объект «прав».

-121--4407470-

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

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

Технически, вы можете записать одну и ту же неизменяемую структуру данных как в C #, так и в F #. Проблема в том, что F # побуждает вас сделать это, в то время как запись истинных неизменяемых структур данных в C # немного болезненна. Это означает, что при написании кода 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 }

Вы также можете записать то же самое в C #, но вам нужно объявить неизменяемую структуру данных с помощью метода WireX , который возвращает клон с измененным полем X , WireY , WireWidth и т.д. Вот неполный пример:

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

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

Это большая работа без какой-либо помощи от компилятора.

5
ответ дан 28 November 2019 в 18:13
поделиться

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

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

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

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

12
ответ дан 28 November 2019 в 18:13
поделиться

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

F # позволяет легко создавать модифицированные копии неизменяемых данных, это очень утомительно и требует много времени для перехода с C #. Рассмотрите возможность создания записи на F #:

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

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

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

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

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

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

] При создании myList, весь myList сохраняется без изменений, а в его заголовок добавляется «4» для создания myList.

3
ответ дан 28 November 2019 в 18:13
поделиться

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

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

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

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

Правка, чтобы ответить на комментарий:

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

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

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

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

3
ответ дан 28 November 2019 в 18:13
поделиться

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

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

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

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

2
ответ дан 28 November 2019 в 18:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: