Что ближе всего к Haskell GADT и классам типов в F#?
F# является ОД с ООП. Что ближе всего подходит к обобщенным алгебраическим типам данных и классам типов Haskell?
2 ответа
Ответ зависит от того, какую проблему вы пытаетесь решить. F# не имеет классов типов и GADT, поэтому прямого отображения нет. Однако F# имеет различные механизмы, которые вы бы использовали для решения проблем, которые вы обычно решаете в Haskell, используя GADT и классы типов:
Если вы хотите представлять объектные структуры и иметь возможность добавлять новые конкретные реализации с другим поведением, то вы часто можете использовать стандартные ОО и интерфейсы.
Если вы хотите написать общий числовой код, вы можете использовать статические ограничения членов ( вот пример), которые, вероятно, технически наиболее близки к типу классов.
Если вы хотите написать более продвинутый общий код (например, универсальный принтер или анализатор), то вы часто можете использовать мощные возможности отражения во время выполнения F#.
Если вам нужно параметризовать код с помощью набора функций (которые выполняют различные подоперации, требуемые кодом), тогда вы можете обойти реализацию интерфейса, как показывает @pad.
Существует также способ эмулировать классы типов Haskell в F#, но обычно это не идиоматическое решение F#, поскольку стиль программирования F# отличается от стиля Haskell по ряду причин. Тем не менее, одним из стандартных применений является определение перегруженных операторов (см. Этот ответ SO).
На метауровне вопрос о том, что эквивалентно признаку X в другом языке, часто приводит к путанице, поскольку X может использоваться для решения проблем A, B, C на одном языке, в то время как другой язык может предоставлять различные функции для решения. те же проблемы (или некоторые проблемы могут вообще не существовать).
В F# вы часто используете интерфейсы и наследование для этих целей.
Для примера, вот простой класс типов с использованием интерфейсов и выражений объектов:
/// Typeclass
type MathOps<'T> =
abstract member Add : 'T -> 'T -> 'T
abstract member Mul : 'T -> 'T -> 'T
/// An instance for int
let mathInt =
{ new MathOps<int> with
member __.Add x y = x + y
member __.Mul x y = x * y }
/// An instance for float
let mathFloat =
{ new MathOps<float> with
member __.Add x y = x + y
member __.Mul x y = x * y }
let XtimesYplusZ (ops: MathOps<'T>) x y z =
ops.Add (ops.Mul x y) z
printfn "%d" (XtimesYplusZ mathInt 3 4 1)
printfn "%f" (XtimesYplusZ mathFloat 3.0 4.0 1.0)
Это может выглядеть не очень красиво, но это F#-ish способ сделать это. Для более похожего на Haskell решения, которое использует словарь операций, вы можете взглянуть на этот хороший ответ.