Размеченные объединения F# и иерархии классов C#

У меня есть следующий код:

public abstract class A ...
public class B : A ...
public class C : A ...

void my_fct(A x) {
  if (x is B) { block_1 }
  else if (x is C) { block_2 }
  else { block_3 }
}

и мне интересно, хороший ли это перевод с F#

type a = B | C
let my_fct x =
  match x with
  | B -> ( block_1 )
  | C -> ( block_2 )
  | _ -> ( block_3 )

??


person Hugo    schedule 07.09.2011    source источник
comment
Думаю, все в порядке. За исключением того, что вам не хватает ; после блока_1, блока_2 и блока_3   -  person Theun Arbeider    schedule 07.09.2011
comment
Извините за невежество, но кажется, что block_3 никогда не может быть выполнено во фрагменте F# (алгебраические типы данных закрыты, насколько я знаю), так почему же он там? Кроме того, я единственный, кто думает, что перевод должен использовать полиморфизм?   -  person    schedule 07.09.2011
comment
Вы абсолютно правы насчет block_3.   -  person Hugo    schedule 07.09.2011
comment
Сопоставление с шаблоном в F# компилируется в переход в сборке, поэтому количество случаев объединения равно O(1). Чтобы соответствовать производительности в C#, у вас должен быть номер регистра кодирования int или enum, а сопоставление с образцом закодировано как инструкция switch.   -  person t0yv0    schedule 07.09.2011


Ответы (2)


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

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

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

let my_fct x = 
  match x with 
  | B -> ( block_1 ) 
  | C -> ( block_2 ) 
person Tomas Petricek    schedule 07.09.2011

да, это более или менее то же самое, что и F#. В этом случае (значения не добавляются) - F #, похоже, переводит это в классы для «a» и некоторые теги (перечисление). Класс для «а» просто имеет некоторые статические свойства для B и C, а также некоторые методы для проверки того, является ли объект типа «а» «В» или «С» (см. ниже)

Обозреватель типов

Но вам не нужен случай "_ -> (block_3)", потому что он никогда не может быть сопоставлен (F# знает все возможные случаи и предупредит вас).

Я думаю, что будет лучше, если вы создадите исключение в C# для этого «иначе».

person Random Dev    schedule 07.09.2011
comment
ну, я думаю, Томас выразился лучше;) - person Random Dev; 07.09.2011