Is it possible to create a polymorphic variant type dynamically using modules? - ocaml

I'm trying to organzine and reuse my reasonML code. I have model module types that look like the following:
module Diet = {
type schemaType = [`DietSchema];
type idType = [`DietId(UUID.t)];
let schema = `DietSchema;
type idAsType('a) = [> | idType] as 'a;
};
module Ingredient = {
type schemaType = [`IngredientSchema];
type idType = [`IngredientId(UUID.t)];
let schema = `IngredientSchema;
type idAsType('a) = [> | idType] as 'a;
};
module Restriction = {
type schemaType = [`RestrictionSchema];
type idType = [`RestrictionId(UUID.t)];
let schema = `RestrictionSchema;
type idAsType('a) = [> | idType] as 'a;
};
And I would like to generate a types and functions from the idTypes and schemaTypes.
examples are:
type modelIdType = [
| Diet.idType
| Restriction.idType
| Ingredient.idType
];
type schemaType = [
| Diet.schemaType
| Restriction.schemaType
| Ingredient.schemaType
];
let modelIdToIdFunction = (recordIdType): (schemaType, UUID.t) =>
switch (recordIdType) {
| `DietId(uuid) => (Diet.schema, uuid)
| `RestrictionId(uuid) => (Restriction.schema, uuid)
| `IngredientId(uuid) => (Ingredient.schema, uuid)
};
So I'm attempting to construct a module using a functor passing each of the schemas through
module Diet : SchemaType = {
/* ... */
};
module type SchemaType {
type schemaType;
type idType;
let schema: [> schemaType];
type idAsType('a) = [> | idType] as 'a;
};
module ProcessSchema = (
Schema : SchemaType,
PrevFullSchema : FullSchema
) : (FullSchema) => {
type id = [> Schema.idType' | PrevFullSchema.id'('a)] as 'a;
/* type id = [PrevFullSchema.openId(PrevFullSchema.id) | Schema.idType]; */
/* type schema = [PrevFullSchema.schema | Schema.schema]; */
/* type openSchema = [PrevFullSchema.schema | Schema.schema]; */
};
The code above didn't work. I'm having trouble adding module types to the model modules at the top. I also attempted through a SchemaType module type but kept hitting The type idType is not a polymorphic variant type, When I wanted each model to have distinct polymorphic variable types.
So overall, I want to know if it is possible to create a polymorphic variant type that can be created or extended using modules and functors?
If not is it possible to construct polymorphic variant types using a "list of modules"?
Thanks

Someone asked a similar question back in 2002. According to one of the OCaml language developers, it's not possible to dynamically extend polymorphic variant types like that: https://caml-list.inria.narkive.com/VVwLM96e/module-types-and-polymorphic-variants . The relevant bit:
The functor definition is refused because
"The type M.t is not a polymorphic variant type"
Is there a workaround?
Not that I know. Polymorphic variant extension only works for known
closed variant types, otherwise it would not be sound.
The rest of the post has a suggestion which boils down to capturing the new variant types inside different tags, but again that wouldn't work for your use case of dynamically 'adding together' types using a functor.

For the types you can use an extensible variant type. But for the modelIdToIdFunction function given a list of modules I think you can only search through the list, which won't scale.
You should extend the uuid with an ID for each module so you can create a lookup table from module_id to the module from the list for fast access.

Related

Use abstract module as part of type definition separate from module

I'm trying to use the module type Partial_information which is constructed via the functor Make_partial_information as the type of the field contents in the type Cell.t. However, I'm getting the error Unbound module Partial_information.
open Core
(* module which is used as argument to functor *)
module type Partial_type = sig
type t
val merge : old:t -> new_:t -> t
end
(* type of result from functor *)
module type Partial_information = sig
type a
type t = a option
val merge : old:t -> new_:t -> t
val is_nothing : t -> bool
end
(* The functor *)
module Make_partial_information(Wrapping : Partial_type):
(Partial_information with type a = Wrapping.t)
= struct
type a = Wrapping.t
type t = a option
let merge ~(old : t) ~(new_ : t) =
match (old, new_) with
| (None, None) -> None
| (None, Some a) -> Some a
| (Some a, None) -> Some a
| (Some a, Some b) -> (Wrapping.merge ~old:a ~new_:b) |> Some
let is_nothing (it: t) : bool = (is_none it)
end
(* Checking to make sure understanding of functor is correct *)
module Int_partial_type = struct
type t = int
let merge ~old ~new_ = new_ [##warning "-27"]
end
module Int_partial_information = Make_partial_information(Int_partial_type)
(* Trying to use _any_ type which might have been created by the functor as a field in the record *)
module Cell = struct
type id = { name : string ; modifier : int }
type t = {
(* Error is here stating `Unbound module Partial_information` *)
contents : Partial_information.t ;
id : id
}
end
Module types are specifications for modules. They do not define types by themselves. They are also not constructed by functors in any way.
Consequently, it is hard to tell what you are trying to do.
As far I can see, you can simply define your cell type with a functor:
module Cell(P : Partial_information) = struct
type id = { name : string ; modifier : int }
type partial
type t = {
contents : P.t;
id : id
}
end
Or it might be even simpler to make the cell type polymorphic:
type 'a cell = {
contents : 'a;
id : id
}
since the type in itself is not particularly interesting nor really dependent upon
the type of contents.
P.S:
It is possible to use first class modules and GADTs to existentially quantify over a specific implementation of a module type. But it is unclear if it is worthwhile to explode your complexity budget here:
type 'a partial_information = (module Partial_information with type a = 'a)
module Cell = struct
type id = { name : string ; modifier : int }
type t = E: {
contents : 'a ;
partial_information_implementation: 'a partial_information;
id : id
} -> t
end

How to implement a module signature in OCaml with some default implementation?

I want to implement a module signature in OCaml like below, where the function get_data depends on each module implementation and return an option type. I also want to provide the function get_data_exn which is a wrapping of get_data by un-optioning the result of get_data, and throwing an exception when the result returned by get_data is None
module type Foo = sig
type t
val get_data : int -> t option
val get_data_exn : int -> t
end
In essence, the implementation of the function get_data_exn will be like below, and it will be the same for all modules that implement Foo:
let get_data_exn value = match get_data value with
| Some data -> data
| None -> raise DataNotFound
Is this possible for me to include this implementation of get_data_exn inside the signature Foo so that I don't have to repeat it for other modules? This is something similar to abstract class in Java.
Thank you for spending time to consider my question.
You can define a core module type
module type Foo_core = sig
type t
val get_data: int -> t option
end
and extend it with a functor:
module Get_data_exn(Core:Foo_core) = struct
let get_data_exn value = match Core.get_data value with
| Some data -> data
| None -> raise DataNotFound
end
Depending on your use case, it might be useful to expose a standard Make_foo functor
module Make_full_Foo(X:Foo_core) = struct
include X
include Get_data_exn(X)
end

Problems using `u8` in Substrate and ink

I am trying to add a simple u8 to my Substrate Runtime Module:
decl_storage! {
trait Store for Module<T: Trait> as TemplateModule {
MyByte: u8;
}
}
However, I get a compiler error that it does not implement Parity Codec's Encode or Decode:
error[E0277]: the trait bound `u8: _IMPL_DECODE_FOR_Event::_parity_codec::Encode` is not satisfied
--> /Users/shawntabrizi/Documents/GitHub/substrate-package/substrate-node-template/runtime/src/template.rs:23:1
|
23 | / decl_storage! {
24 | | trait Store for Module<T: Trait> as TemplateModule {
25 | | MyByte: u8;
26 | | }
27 | | }
| |_^ the trait `_IMPL_DECODE_FOR_Event::_parity_codec::Encode` is not implemented for `u8`
A similar problem occurs when I try to store a u8 in a Substrate Smart Contract using ink!:
contract! {
struct MyContract {
value: storage::Value<u8>,
}
...
}
Error:
error[E0277]: the trait bound `u8: parity_codec::codec::Encode` is not satisfied
--> src/lib.rs:26:1
|
26 | / contract! {
27 | | struct MyContract {
28 | | value: storage::Value<u8>,
29 | | }
... |
49 | | }
50 | | }
| |_^ the trait `parity_codec::codec::Encode` is not implemented for `u8`
Why is that, and what can I do to resolve the issue?
Today, the parity_codec does not support Encoding of u8 due to avoid a type collision, since Vec<u8> is a special case from Vec<T>.
See: https://github.com/paritytech/parity-codec/issues/47
gavofyork:
Because it would otherwise make the two encodings: Vec<u8> and Vec<T: Codec> clash.
It is possible this could be fixed in the future with additional Rust features, but for now, you will need to store your single bytes as [u8; 1] and work with that type.
Substrate Runtime Module
One hacky solution for a Substrate Runtime Module looks something like this:
use support::{decl_module, decl_storage, decl_event, StorageValue, dispatch::Result};
use system::ensure_signed;
pub trait Trait: system::Trait {
type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
}
type U8 = [u8; 1];
decl_storage! {
trait Store for Module<T: Trait> as TemplateModule {
MyByte get(my_byte): U8;
}
}
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
fn deposit_event<T>() = default;
pub fn set_my_byte(origin, input: U8) -> Result {
let who = ensure_signed(origin)?;
<MyByte<T>>::put(input);
Self::deposit_event(RawEvent::MyByteStored(input, who));
Ok(())
}
pub fn add_to_byte(origin, input: U8) -> Result {
let who = ensure_signed(origin)?;
let my_byte = Self::my_byte()[0];
let my_new_byte = my_byte.checked_add(input[0]).ok_or("Overflow")?;
<MyByte<T>>::put([my_new_byte]);
Self::deposit_event(RawEvent::MyByteStored([my_new_byte], who));
Ok(())
}
}
}
decl_event!(
pub enum Event<T> where AccountId = <T as system::Trait>::AccountId {
MyByteStored(U8, AccountId),
}
);
Where we assign a new type type U8 = [u8; 1];. The choice of our new type name is important since it will trick the Polkadot UI to treat this value simply as a u8 for any input/output fields it generates. If you try to use a custom type like type Byte = [u8; 1], the UI will ask you to import the definition of that custom type. If you try to use [u8; 1] directly, the Polkadot UI will not know how to render the input/output of that value.
Furthermore, as of the time of writing this post, the decl_event! macro has an issue depositing a [u8; 1] directly due to pattern matching.
Note that you will need to treat this type like an array when you use it. add_to_byte() shows an example of that. So ultimately, you need to extract the first item of the array to extract the byte, and you need to wrap your byte in an array to set a U8:
let my_byte = Self::my_byte()[0];
...
<MyByte<T>>::put([my_new_byte]);
Other solutions may involve using other types which are natively supported like Vec<u8> or u16, and doing the appropriate checks on your runtime that this is treated like a single u8, but the UI will not know better.
Substrate Smart Contracts
I have not found a great solution for ink! yet, but you should be able to use [u8; 1] directly in all of your code. Again, you will need to treat it like an array for getters and setters. But when generating the ABI you will need to manually change the instances of [u8; 1] to u8 to trick the UI to do what you want.

type mismatch error declaring list of classes

def getValueAndItsType() : List[ (AnyRef, Class[_]) ] = {
val dataSet1 = ("some string data", classOf[String])
val dataSet2 = (new Thread(), classOf[Thread])
val dataSet3 = (new NullPointerException(), classOf[NullPointerException])
val dataSet4 = (5, classOf[Int])
val list = List(dataSet1, dataSet2, dataSet3, dataSet4)
list
}
Type type mismatch; found :
List[(Any, Class[_ >: Int with NullPointerException with Thread with
String])] required: List[(AnyRef, Class[_])]
If dataSet4 is removed from List, the compile time error disappears
Please suggest, what is wrong with Class[_]. Isn't it
equivalent to Class[?] in java ? I appreciate, if you also suggest
correct declaration for doing this..
In Scala:
Any is the root of the Scala class.
AnyRef is the root of the class of reference types, it extends from Any.
AnyVal is the root class of all value types. it extends from Any
Null is a subtype of all reference types.
Nothingis a subtype of all other types including Null
So base on your code, you need to extend from Any, include AnyRef: reference types and AnyVal: values types.
def getValueAndItsType() : List[ (Any, _ <: Any) ] = {
val dataSet1 = ("some string data", classOf[String])
val dataSet2 = (new Thread(), classOf[Thread])
val dataSet3 = (new NullPointerException(), classOf[NullPointerException])
val list = List(dataSet1, dataSet2, dataSet3)
list
}

Functors with multiple inputs in Standard ML

High level question: How do I use functors with multiple arguments in SML?
I've looked at this, this, this and this(PDF). All of them seem to conflict in terms of structure or functor definition syntax, and none of them show anything other than a unary functor.
Specifics: I'm trying to write a web server in Standard ML (you can see the effort here), and have decided to partition it into BUFFER, PARSER and TCPSERVER chunks. The BUFFER and PARSER are both just straightforward structures. The idea with the TCPSERVER is that it handles listening/accepting logic, but allows the user to specify an appropriate buffering/parsing strategy by passing the other two in. What I've got is something like
signature TCPSERVER =
sig
type SockAction
type Request
val serve : int -> (Request -> (INetSock.inet,Socket.active Socket.stream) Socket.sock -> SockAction) -> 'u
end
functor Server (Buf : BUFFER) (Par : PARSER) : TCPSERVER =
struct
type Request = Par.Request
datatype SockAction = CLOSE | LEAVE_OPEN
local
...
[eliding more definitions, including calls to Par.* and Buf.* functions]
...
fun serve port serverFn =
let val s = INetSock.TCP.socket()
in
Socket.Ctl.setREUSEADDR (s, true);
Socket.bind(s, INetSock.any port);
Socket.listen(s, 5);
print "Entering accept loop...\n";
acceptLoop s [] serverFn
end
end
end
The above seems to be accepted by smlnj...
- use "server.sml" ;
[opening server.sml]
type Response =
{body:string, headers:(string * string) list, httpVersion:string,
responseType:string}
val fst = fn : 'a * 'b -> 'a
val snd = fn : 'a * 'b -> 'b
val a_ = fn : 'a * 'b * 'c -> 'a
val b_ = fn : 'a * 'b * 'c -> 'b
val c_ = fn : 'a * 'b * 'c -> 'c
val curry = fn : ('a * 'b -> 'c) -> 'a -> 'b -> 'c
signature TCPSERVER =
sig
type SockAction
type Request
val serve : int
-> (Request
-> (INetSock.inet,Socket.active Socket.stream) Socket.sock
-> SockAction)
-> 'a
end
functor HTTPServer(Buf: sig
type Buffer
val readInto : Buffer
-> ('a,Socket.active Socket.stream)
Socket.sock
-> BufferStatus
val new : int -> Buffer
val toSlice : Buffer -> Word8ArraySlice.slice
val printBuffer : Buffer -> unit
end) :
sig functor <functor> : <fctsig> end
val it = () : unit
... but rejected by mlton.
~/projects/serve-sml $ mlton server.mlb
Error: server.sml 23.1. # (line with "functor Server...")
Syntax error: replacing FUNCTOR with FUN.
Error: server.sml 24.1.
Syntax error: replacing STRUCT with ASTERISK.
Error: server.sml 87.1.
Syntax error found at END.
Error: server.sml 88.0.
Parse error.
...
Additionally, I'm not entirely sure how to use the definition once it's evaluated. Even in smlnj, the obvious fails:
- HTTPServer(DefaultBuffer, DefaultParser) ;
stdIn:1.2-1.12 Error: unbound variable or constructor: HTTPServer
stdIn:2.7-3.1 Error: unbound variable or constructor: DefaultParser
stdIn:1.13-2.5 Error: unbound variable or constructor: DefaultBuffer
-
Can anyone tell me what I'm doing wrong? Or even point me to a good piece of documentation?
Your Server functor does multiple arguments via currying. That does not work in plain SML, because it does not have higher-order functors (which SML/NJ supports as a non-standard extension). You need to use uncurried form, by introducing an auxiliary structure, like you would use a tuple or record in the core language:
functor Server(X : sig structure Buffer : BUFFER; structure Parser : PARSER end) =
...X.Buffer...X.Parser...
structure MyServer =
Server(struct structure Buffer = MyBuffer; structure Parser = MyParser end)
Obviously, this is pretty clumsy and verbose, so at least SML has some syntactic sugar for the above, allowing you to keep the auxiliary structure implicit:
functor Server(structure Buffer : BUFFER; structure Parser : PARSER) =
...Buffer...Parser...
structure MyServer =
Server(structure Buffer = MyBuffer; structure Parser = MyParser)
But that is as short as it gets in current SML.
It's useful to understand that Standard ML is composed of two languages — the core language of values (ordinary functions, numbers, booleans, their types, etc.) and the language of modules, comprised of signatures, structures and functors.
Functors are similar to core functions, they always accept a single argument and return a module-level value. A functor's argument type is specified by a signature, while the actual value of the argument, when "calling" the functor, will be a structure implementing that signature. A functor returns a structure, whose type is again determined by a signature. This is the basic skeleton:
signature ARG = sig end
signature RESULT = sig end
functor FUNCTOR(A : ARG) : RESULT
Now, as mentioned and examplified by Andreas Rossberg, the standard provides some syntactic sugar for expressing a functor's param type. However, I tend to favor the above skeleton when a functor requires more than a few structures as input:
signature SERVER_ARGS =
sig
structure ARG_0 = sig end
structure ARG_1 = sig end
structure ARG_2 = sig end
structure ARG_3 = sig end
end
signature SERVER = sig end
functor ServerFn(ARGS : SERVER_ARGS) : SERVER =
struct
end
Now, when calling a functor, there are several choices as to the syntax:
(* Using an anonymous structure *)
ServerFn(struct
structure ARG_0 = struct end
structure ARG_1 = struct end
structure ARG_2 = struct end
structure ARG_3 = struct end
end)
(* Using a named structure *)
structure ServerArgs =
struct
structure ARG_0 = struct end
structure ARG_1 = struct end
structure ARG_2 = struct end
structure ARG_3 = struct end
end
ServerFn(ServerArgs)
(* Using an anonynous structure, with syntactic sugar *)
ServerFn(
structure ARG_0 = struct end
structure ARG_1 = struct end
structure ARG_2 = struct end
structure ARG_3 = struct end
)
A functor's result, being a structure, may only be found in a structure position in source code, i.e., you either give it a name using the structure keyword, or you pass it along as an argument to some other functor:
structure Server = ServerFn(ServerArgs)
structure Quux = OtherFunctor(ServerFn(ServerArgs))
The structure keyword is the module-level equivalent of the val keyword in the core language. A way to bind "variables" at the module level. In the same vein, the signature keyword is the module-level equivalent of the type keyword in the core language — a helpful way to introduce aliases for anonymous signatures denoted by sig ... end.
This is why your last example fails, because the SML top-level tries to interpret HTTPServer(DefaultBuffer, DefaultParser); as a core-level function call, not as a module-level function/functor call.
I think the StandardML syntax for multi-argument functors is:
signature PARSER = sig
val parse : unit -> unit
end
signature BUFFER = sig
val read : unit -> unit
end
functor Server (structure buffer : BUFFER
structure parser : PARSER) = struct
end
I guess the issue is that SML-NJ supports higher-order functors while MLton does not.