Я пытаюсь перевести Arrows базовой библиотеки Haskell в F # (я думаю, что это хорошее упражнение для лучшего понимания Arrows и F #, и я мог бы использовать их в проекте, над которым я работаю.) Однако,прямой перевод невозможен из-за разницы в парадигмах.Haskell использует классы типов для выражения этого материала, но я не уверен, что конструкции F # лучше всего отображают функциональность классов типов с идиомами F #.У меня есть несколько мыслей, но я решил, что лучше поднять это здесь и посмотреть, что считается наиболее близким по функциональности.
Для толпы троллей: Как мне перевестиклассы типов (идиома 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
Первым делом я попытался просто сопоставить вещи напрямую, используя Модули для организации,как:
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 нельзя использовать повторно (для обеспечения типов функций let bound) для других реализаций и переименования типов/ инкапсулировать вещи сложно.
Попытка 2: объектные модели и интерфейсы
Рационализация того, что F # также построен как OO, возможно, иерархия типов является правильным способомсделайте это.
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 #.Были ли мои попытки близки?Кто-нибудь из них "настолько хорош, насколько это возможно", и этого должно быть достаточно?