Я пытаюсь написать функцию, которая принимает определенный тип или любой из его подтипов в качестве одного из аргументов, а затем возвращает значение типа или любого из его подтипов.
[<AbstractClass>]
type Spreader () =
abstract Fn : unit -> unit
type Fire () =
inherit Spreader ()
override self.Fn () = ()
type Disease () =
inherit Spreader ()
override self.Fn () = ()
let spread (spr:#Spreader) : #Spreader =
match spr with
| :? Fire -> Fire ()
| :? Disease -> Disease ()
| _ -> failwith "I don't get it"
Очевидно, это не работает, но вы получаете то, что я пытаюсь сделать.
Сначала я реализовал абстрактную функцию в типе Spreader и переопределил (переопределил?) Ее в подпрограмме.типы, но это требовало апскейтинга, которого я пытаюсь избежать.
Это выполнимо?Я изучаю дженерики, но я не совсем понял их реализацию F #.
РЕДАКТИРОВАТЬ 2010.07.08 1730 PST
Что касается предположения, что яиспользовать дискриминационные союзы, я пробовал это раньше.Проблема, с которой я столкнулся, заключалась в том, что любая функция, которую я определил как член базового типа, должна была обрабатывать каждую ветвь объединения.Например:
type strength = float32
type Spreader =
| Fire of strength
| Disease of strength
member self.Spread () =
match self with
| Fire str -> Fire str
| Disease str -> Disease str
member self.Burn () =
match self with
| Fire str -> Fire str
| _ -> failwith "Only fire burns"
Здесь хорошо работает функция Spread, но если я хочу, чтобы Fire горел, то я должен также предусмотреть Disease, что не имеет смысла.
Я хочучтобы учесть возможные попытки пользователя сделать что-то нелегальное, например, попытку Disease.Burn, но я не хочу возвращать повсюду несколько типов опций, например:
member self.Burn () =
match self with
| Fire str -> Some(Fire str)
| _ -> None
Я бы предпочел просто оставить функцию Burn строго для Spreader, и даже не определять ее для Disease Spreader.
Кроме того, это касается и свойств;Есть некоторые члены, которые, как я хочу, чтобы у Fire был смысл, для Disease, и наоборот.Кроме того, я хотел бы иметь возможность получить доступ к значению силы Spreader с помощью точечной нотации, поскольку у меня будут другие члены, к которым я получаю доступ в любом случае, и, как ни странно, излишне иметь необходимость определять member.strength после того, как он ужезаключен в объекте.(например, | Disease str -> ...)
Другой вариант, конечно, состоит в том, чтобы просто отделить функции Spread и Burn от типа Spreader, но тогда я должен либо (1) предоставить некрасивую апскейтинг, либоуниверсальный код для функций (как уже описывали другие), или (2) имеют полностью отдельные функции для Fire и Disease, которые могут быть отстойными в случае Spread, поскольку я должен был бы назвать их SpreadFire и SpreadDisease (так как функция перегружает внешние типыкак ни странно, не допускается).
Как новичок в F #, я приветствую все критические замечания и предложения.:)
РЕДАКТИРОВАТЬ 2010.07.09 0845 PST
Джон Харроп: «Почему вы используете дополнения и элементы?»
Поскольку типы в моем реальном коде интенсивно используют математику, поэтому я предварительно вычисляю некоторые значения при инициализации и сохраняю их как элементы.
Джон Харроп: «Почему вы хотите, чтобы запись горения применялась к Speader?типы, когда это применимо только к одному? "
Как я уже писал, я не хочу, чтобы Burn применился к Spreader.Я хочу, чтобы это относилось исключительно к Огню.Однако я разрывался между реализацией функции как члена Spreader и отделением ее от типа Spreader.(Запах непоследовательности.)
Джон Харроп: «Какова цель вашего члена Fn?»
Извините, это был просто посторонний код, пожалуйста, игнорируйте его.
Джон Харроп: «Почему вы использовали абстрактный интерфейс вместо интерфейса?»
Преимущественно читаемость и эффективность кода.Ненавижу переходить на интерфейс только для того, чтобы использовать один из его методов.
Джон Харроп: «Почему вы определили силу как псевдоним для float32?»
Читаемость кода.
Джон Харроп: «Какую конкретную проблему вы пытаетесь решить?!»
Совместное использование кода для связанных типов при сохранении читаемости.
Интересно, что решение, которое вы предложили, - это именно то решение, которое я впервые попробовал (я занимался этим F # всего неделю или около того), но я отказался от него, потому что мне было неловко от мысли о необходимости обернутьмои фундаментальные типы в DU как обходной путь для неспособности перегрузить функции, определенные вне определений типов.Я просто очень параноидален по поводу того, что могу ошибиться с фундаментальными типами (отчасти из-за печального отсутствия рефакторинга F # в VS2010).Функциональное программирование является предметом большого интереса для меня прямо сейчас, и я в значительной степени просто пытаюсь найти понимание.
РЕДАКТИРОВАТЬ 2010.07.09 2230 PST
На самом делеЯ начинаю не любить функциональное программирование (действительно согласен с автором в http://briancarper.net/blog/315/functional-programming-hurts-me - если я увижу еще один пример кодирования Фибоначчи или факториала в учебнике или учебнике по F #, я собираюсь нанести удар следующимботаник, я нахожу).
Я надеялся, что кто-то здесь ответит на мой последний ответ (объясняя, почему я делаю определенные вещи) с видом презрения, которое Джон продемонстрировал (ниже).Я хочу изучать FP у надменной элиты, кодеров, которые думают, что их дерьмо не воняет.