I am working on an exercise, whence I am trying to define some basic algorithms on arrays. Since arrays naturally includes string interfaces, I would like to also make sure that the infrastructure includes the possibility of using strings as input. I noticed that the way the strings are defined in the standard library (whether Stdlib or Base) is along the following lines:
module type STRING = sig
type t
type item
val get : t -> int -> item
end
module String : STRING
whereas the definition for arrays is
module type ARRAY = sig
type 'a t
val get : 'a t -> int -> 'a
end
module Array : ARRAY
While trying to reconcile the differences in the type t
arity in my interfaces, I have attempted the following approach to represent strings with an array
module Array_constrained
(Itm : ITEM) =
struct
module type S = sig
type 'a t constraint 'a = Itm.t
val get : 'a t -> int -> 'a
end
end
Then I hoped to be able to use implement an interface that implements operations common to strings and arrays by doing the following:
module Common_ops
(A : ARRAY) :
sig
val opus : 'a A.t -> int -> unit
end =
struct
(* implementation *)
end
and then use the result in the module implementing string operations as follows
module String_ops
(Itm : ITEM)
(Str : STRING) =
struct
module Immutable_array :
Array_constrained(Itm).S =
struct
type 'a t = Str.t
let get = Str.get
end
include Common_ops(Immutable_array)
end
However, the functors that take type ARRAY
do not take the type Array_constrained(Itm)
. Logically, it seems that setting variance on 'a t
should have worked, since a constrained 'a
in 'a t
means that 'a
has a narrower domain, and hence so does 'a t
, which is precisely the basic concept that the variance should be representing. Yet, it does not. I am still getting an error about mismatching constraints in signatures.
I expected that Common_ops
would be yielding an implementation with 'a
in the type 'a A.t
constrained in the same way as it has been in the input module A
. Thus, passing a module matching Array_constrained(Itm).S
to Common_ops
should have yielded the interface of Common_ops
with value opus
taking values of type 'a A.t constraint 'a = Itm.t
.
Could you please assist me with finding how to solve this problem, so that I would either be able to apply modules with constrained signature, or perhaps find some other approach to implementing interfaces that work both with STRING
and ARRAY
inputs, and in which common operations could be provided without code duplication. The solution whence e.g. two versions of Common_ops
module provided, one for STRING
and one for ARRAY
is not acceptable.
Additional notes. Please note that it is undesirable to introduce interfaces whence the value of t
would not be polymorphic, and the type of items stored in the container would be provided by a functor argument, even for arrays. In principle, such solution would be easy, and I have attempted it myself. However, I am at a loss, how to implement such solution so that it would result in a model signature with polymorphic 'a t
. I am aware that it could be done with first-class modules and having a function produce output with polymorphic 'a t
(while using the non-polymorphic 'a t
to implement the modules it would be giving out as a result). However, I am not aware as to how I could make such a function to produce a static module of the required type. Is that even possible? Would the performance of the resulting modules be less efficient than in the case whence the first-class modules are not used? Please feel free to as for additional clarifications on these notes.