Ответ 1
Во-первых, здесь приведена автономная версия вашего кода (используя устаревшее
List.fold_left
стандартной библиотеки) для людей, которые не имеют
Ядро под рукой и все еще хочу попытаться скомпилировать ваш пример.
module type MonadSig = sig
type 'a t
val bind : 'a t -> ('a -> 'b t) -> 'b t
val return : 'a -> 'a t
end
let sequence (module M : MonadSig) foo =
let open M in
let (>>=) = bind in
List.fold_left (fun acc x ->
acc >>= fun acc' ->
x >>= fun x' ->
return (x' :: acc')
) (return []) foo;;
Сообщение об ошибке, которое вы получаете (путающая первая строка может
следует игнорировать), что определение M.t является локальным для модуля M
, и
не должен сдерживать его масштабы, что он будет делать с тем, что вы пытаетесь
для записи.
Это потому, что вы используете первоклассные модули, которые позволяют
абстрактные модули, но не имеющие зависимые типы, такие как
тип возвращаемого значения зависит от значения параметра аргумента или, по меньшей мере,
path (здесь M
).
Рассмотрим следующий пример:
module type Type = sig
type t
end
let identity (module T : Type) (x : T.t) = x
Это неправильно. Сообщения об ошибках указывают на (x : T.t)
и говорят:
Error: This pattern matches values of type T.t
but a pattern was expected which matches values of type T.t
The type constructor T.t would escape its scope
То, что вы можете сделать, - это абстрактное задание по желаемому типу, прежде чем абстрагироваться на модуле первого класса T, чтобы больше не было выхода.
let identity (type a) (module T : Type with type t = a) (x : a) = x
Это зависит от способности явно абстрагироваться от переменной типа a
. К сожалению, эта функция не была расширена до абстракции над более высокоразвитыми переменными. Вы не можете писать:
let sequence (type 'a m) (module M : MonadSig with 'a t = 'a m) (foo : 'a m list) =
...
Решение состоит в использовании функтора: вместо работы на уровне значения вы работаете на уровне модуля, который имеет более богатый родной язык.
module MonadOps (M : MonadSig) = struct
open M
let (>>=) = bind
let sequence foo =
List.fold_left (fun acc x ->
acc >>= fun acc' ->
x >>= fun x' ->
return (x' :: acc')
) (return []) foo;;
end
Вместо того, чтобы выполнять каждую монадическую операцию (sequence
, map
и т.д.) абстрактно над монадой, вы выполняете абстракцию по всему модулю.