Подтвердить что ты не робот

Конструкторы и функторы более высокого порядка в Ocaml

Могут ли следующие полиморфные функции

let id x = x;;
let compose f g x = f (g x);;
let rec fix f = f (fix f);;     (*laziness aside*)

записывается для типов/типов конструкторов или модулей/функторов? Я попробовал

type 'x id = Id of 'x;;
type 'f 'g 'x compose = Compose of ('f ('g 'x));;
type 'f fix = Fix of ('f (Fix 'f));;

для типов, но он не работает.

Здесь версия Haskell для типов:

data Id x = Id x
data Compose f g x = Compose (f (g x))
data Fix f = Fix (f (Fix f))

-- examples:
l = Compose [Just 'a'] :: Compose [] Maybe Char

type Natural = Fix Maybe   -- natural numbers are fixpoint of Maybe
n = Fix (Just (Fix (Just (Fix Nothing)))) :: Natural   -- n is 2

-- up to isomorphism composition of identity and f is f:
iso :: Compose Id f x -> f x
iso (Compose (Id a)) = a
4b9b3361

Ответ 1

Haskell позволяет использовать переменные типа более высокого типа. ML-диалекты, включая Caml, допускают только переменные типа "*". Перевод на простой английский,

  • В Haskell переменная типа g может соответствовать "конструктору типа", подобному Maybe или IO или спискам. Таким образом, g x в вашем примере Haskell будет в порядке (жаргон: "доброжелательный" ), если, например, g есть Maybe и x is Integer.

  • В ML переменная типа 'g может соответствовать только "наземному типу", подобному int или string, никогда к конструктору типа, подобному option или list. Поэтому никогда не следует пытаться применить переменную типа к другому типу.

Насколько мне известно, нет серьезной причины этого ограничения в ML. Наиболее вероятным объяснением является историческая непредвиденная ситуация. Когда Мильнер изначально придумывал свои идеи о полиморфизме, он работал с очень простыми переменными типа, стоящими только для монотипов рода *. Ранние версии Haskell делали то же самое, а затем в какой-то момент Марк Джонс обнаружил, что определение типов переменных типа на самом деле довольно просто. Haskell был быстро пересмотрен, чтобы позволить переменным типа более высокого уровня, но ML никогда не догонял.

Люди из INRIA внесли много других изменений в ML, и я немного удивлен, что они никогда не делали этого. Когда я программирую в ML, мне могут нравиться переменные типа более высокого типа. Но их там нет, и я не знаю, как кодировать примеры, о которых вы говорите, кроме как с помощью functors.

Ответ 2

Вы можете сделать что-то подобное в OCaml, используя вместо модулей типы вместо типов и функторы (модули более высокого порядка) вместо типов более высокого порядка. Но он выглядит намного уродливее, и он не обладает способностью ввода-вывода, поэтому вам нужно вручную указать много вещей.

module type Type = sig
  type t
end

module Char = struct
  type t = char
end

module List (X:Type) = struct
  type t = X.t list
end

module Maybe (X:Type) = struct
  type t = X.t option
end

(* In the following, I decided to omit the redundant
   single constructors "Id of ...", "Compose of ...", since
   they don't help in OCaml since we can't use inference *)

module Id (X:Type) = X

module Compose
  (F:functor(Z:Type)->Type)
  (G:functor(Y:Type)->Type)
  (X:Type) = F(G(X))

let l : Compose(List)(Maybe)(Char).t = [Some 'a']

module Example2 (F:functor(Y:Type)->Type) (X:Type) = struct
  (* unlike types, "free" module variables are not allowed,
     so we have to put it inside another functor in order
     to scope F and X *)
  let iso (a:Compose(Id)(F)(X).t) : F(X).t = a
end

Ответ 3

Ну... Я не эксперт по типам более высокого порядка и программирования Haskell. Но это похоже на F # (это OCaml), вы могли бы работать с ними:

type 'x id = Id of 'x;;
type 'f fix = Fix of ('f fix -> 'f);;
type ('f,'g,'x) compose = Compose of ('f ->'g -> 'x);;

Последний, который я завернул в кортеж, так как я не придумал ничего лучшего...

Ответ 4

Вы можете сделать это, но вам нужно сделать несколько трюков:

newtype Fix f = In{out:: f (Fix f)}

После этого вы можете определить Cata:

Cata :: (Functor f) => (f a -> a) -> Fix f -> a
Cata f = f.(fmap (cata f)).out

Это определит общий катаморфизм для всех функторов, который вы можете использовать для создания собственных вещей. Пример:

data ListFix a b = Nil | Cons a b
data List a = Fix (ListFix a)
instance functor (ListFix a) where
fmap f Nil = Nil
fmap f (Cons a lst) = Cons a (f lst)