Я пытаюсь написать функцию, которая принимает определенный тип или любой из его подтипов в качестве одного из своих аргументов, а затем возвращает значение типа или любого из его подтипов.Функция с аргументом гибкого типа и возвращаемым значением?
[<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 #.
EDIT 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 работает отлично, но если я хочу огня Ожог, то я должен обеспечить болезни, тоже, что не имеет никакого смысла.
Я хочу, чтобы учесть возможные попытки пользователя сделать что-то незаконное, как пытаются Disease.Burn, но я не хочу, чтобы вернуть кучу типов параметров повсюду, например:
member self.Burn() =
match self with
| Fire str -> Some(Fire str)
| _ -> None
Я предпочел бы просто оставить функцию Burn строго для Распределителя огня, и даже не определил его для Рассеивателя болезней.
Кроме того, это относится и к свойствам; есть некоторые члены, которых я хочу, чтобы огонь имел то, что не имеет смысла для болезни, и наоборот. Кроме того, я хотел бы получить доступ к значению силы Spreader с использованием точечной нотации, так как у меня появятся другие члены, которые мне так или иначе получат доступ, и, похоже, любопытно избыточно, что нужно определить member.strength после того, как оно уже инкапсулированный в объект. (например, | Disease str -> ...)
Другой вариант, конечно же, состоит в том, чтобы просто отделить функции Spread and Burn от типа Spreader, но тогда я должен либо (1) предоставить уродливое повышение или общий код для функций (как описывали другие), или (2) имеют полностью отдельные функции для Огня и Болезни, которые сосали бы в случае Спреда, поскольку я должен был бы назвать их SpreadFire и SpreadDisease (поскольку любопытна функция перегрузки внешних типов не допускается).
Как noob для F #, я приветствую все критические замечания и предложения. :)
EDIT 2010.07.09 0845 PST
Джон Harrop: "Почему вы используете аугментаций и члены?"
Поскольку типы в моем фактическом коде являются интенсивными в математике, поэтому я предварительно вычисляю определенные значения при инициализации и сохраняю их как членов.
Jon Harrop: «Почему вы хотите, чтобы ожог применялся к типам Speader, когда он применим только к одному?"
Как я уже писал, я не хочет записать, чтобы применить к распределителю. Я хочу, чтобы применить только к огню. Я был разорван, однако, между реализацией функции в качестве члена Отвода и отделения это от типа Распределитель (Несогласованность запах.)
Jon Harrop:. "Какова цель вашего члена Fn?"
к сожалению, это был просто посторонний код, пожалуйста, игнорируйте его
.Jon Harrop: «Почему вы использовали абстрактный класс вместо интерфейса?»
Продовольствие и эффективность кода в основном. Ненавижу, что мне нужно переходить на интерфейс, чтобы использовать один из его методов.
Jon Harrop: «Почему вы определили силу как псевдоним для float32?»
Читаемость кода.
Jon Harrop: «Какова конкретная конкретная проблема, которую вы пытаетесь решить ?!»
Обмен кодами для родственных типов при сохранении читаемости.
Интересно, что решение, которое вы предложили, является именно тем решением, которое я впервые попробовал (я был на этом F # всего лишь неделю или около того), но я отбросил его, потому что мне было некомфортно с идеей иметь оберните мои фундаментальные типы в DU как обход, чтобы не перегружать функции, определенные определениями внешнего типа. Я просто параноик о выходе на неправильную ногу с фундаментальными типами (частично из-за плачевного отсутствия рефакторинга F # в VS2010). Функциональное программирование является предметом большого интереса для меня прямо сейчас, и я в значительной степени просто ловить рыбу для понимания.
EDIT 2010.07.09 2230 PST
На самом деле, я/м, начиная не нравится функционального программирования (на самом деле согласен с автором в http://briancarper.net/blog/315/functional-programming-hurts-me - если я вижу еще один Фибоначчи или факториал пример кода в F # учебник или учебник, я собираюсь нанести удар по следующему кретину, который я нахожу).
Я надеялся, что кто-то здесь отстрелит мой последний ответ (объясняя, почему я делаю определенные вещи) с видом презрения, которое Джон выставил (ниже). Я хочу узнать FP из надменных элит, кодеров, которые думают, что их sh * t не воняет.
Я DON» у меня есть много чего сказать, чем у Джона, Брайана и Томаса, но для чего стоит, если вы обнаружите, что сражаетесь и взламываете язык, чтобы заставить что-то работать, это почти всегда означает, что вы делаете что-то неправильно. В этом случае наследование не является обычно используемой идиомой в C#, вы определенно хотите использовать что-то более идиоматическое, вроде подобных союзов, которое вы можете сопоставить вместо классов.Не обескураживайте, почти каждый пишет C# с синтаксисом F # при первом использовании (http://stackoverflow.com/questions/1883246/). Как только вы освоите идиомы, использование языка легко *. – Juliet
Спасибо за совет, Джульетта. Я буду помнить ваши предупреждения. На данный момент я пошел с предложением Джона (что иронически является самым первым решением, которое я произвел в этом проекте). – MiloDC