Как мне перевести класс типа Haskell в F #?

Я пытаюсь перевести стрелки базовой библиотеки Haskell на F # (я думаю это хорошее упражнение для лучшего понимания Arrows и F #, и я мог бы использовать их в проекте, над которым я работаю.) Однако прямой перевод невозможен из-за разницы в парадигмах. Haskell использует классы типов для выражения этого материала, но я не уверен, какие конструкции F # лучше всего отображают функциональность классов типов с идиомами F #. У меня есть несколько мыслей, но я решил, что лучше поднять его здесь и посмотреть, что считается наиболее близким по функциональности.

Для толпы tl; dr: Как мне перевести классы типов (идиома Haskell) в идиоматический код F #?

Для тех, кто принимает мое длинное объяснение:

Этот код из стандартной библиотеки Haskell является примером того, что я пытаюсь для перевода:

class Category cat where
    id :: cat a a
    comp :: cat a b -> cat b c -> cat a c
class Category a => Arrow a where
    arr :: (b -> c) -> a b c
    first :: a b c -> a (b,d) (c,d)

instance Category (->) where
    id f = f
instance Arrow (->) where
    arr f = f
    first f = f *** id

Попытка 1: Модули, Простые типы, Let Bindings

Моей первой попыткой было просто сопоставить вещи напрямую, используя Модули для организации, например:

type Arrow<'a,'b> = Arrow of ('a -> 'b)

let arr f = Arrow f
let first f = //some code that does the first op

Это работает, но теряет полиморфизм , поскольку я не реализую категории и не могу легко реализовать более специализированные стрелки.

Попытка 1a: Уточнение с использованием сигнатур и типов

Один из способов исправить некоторые проблемы с Попыткой 1 - использовать файл .fsi для определения методов (чтобы типы выполнялись проще) и использовать некоторые простые настройки типов для специализации .

type ListArrow<'a,'b> = Arrow<['a],['b]>
//or
type ListArrow<'a,'b> = LA of Arrow<['a],['b]>

Но файл fsi может ' t могут быть повторно использованы (для принудительного применения типов связанных функций let) для других реализаций, а переименование / инкапсуляция типов является сложной задачей.

Попытка 2: объектные модели и интерфейсы

Обоснование того, что F # также создан как объектно-ориентированный , может быть, иерархия типов - правильный способ сделать это.

type IArrow<'a,'b> =
    abstract member comp : IArrow<'b,'c> -> IArrow<'a,'c>
type Arrow<'a,'b>(func:'a->'b) = 
    interface IArrow<'a,'b> with
        member this.comp = //fun code involving "Arrow (fun x-> workOn x) :> IArrow"

Помимо того, насколько сложно получить статические методы (такие как comp и другие операторы), которые должны действовать как методы экземпляра, также необходимо чтобы явно улучшить результаты. Я также не уверен, что эта методология по-прежнему отражает всю выразительность полиморфизма классов типов. Это также затрудняет использование вещей, которые ДОЛЖНЫ быть статическими методами.

Попытка 2a: Уточнение с использованием расширений типов

Итак, еще одно возможное усовершенствование - объявить интерфейсы как можно более простыми, затем используйте методы расширения, чтобы добавить функциональность ко всем типам реализации.

type IArrow<'a,'b> with
    static member (&&&) f = //code to do the fanout operation

Ах, но это заставляет меня использовать один метод для всех типов IArrow. Что я могу сделать, если мне нужен немного другой (&&&) для ListArrows? Я еще не пробовал этот метод, но полагаю, что могу затенять (&&&) или, по крайней мере, предоставить более специализированную версию, но мне кажется, что я не могу принудительно использовать правильный вариант.

Помогите мне

Итак, что мне здесь делать? Я чувствую, что объектно-ориентированный подход должен быть достаточно мощным, чтобы заменить классы типов, но я не могу понять, как это сделать в F #. Были ли какие-нибудь из моих попыток закрытыми? Кто-нибудь из них «настолько хорош, насколько это возможно», и этого должно быть достаточно?

43
задан CodexArcanum 27 October 2010 в 15:34
поделиться