Что ближе всего к 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 решения, которое использует словарь операций, вы можете взглянуть на этот хороший ответ.

Другие вопросы по тегам