Let's say that I have a 1 -> n relation: one todo can has many (or zero) notes and a note can have zero or one todo. How can I achieve this relation in ReasonML? (binding for an external lib)
Here is what I have come with at the moment (which is of course not working)
module Note = {
module Attributes = {
[#bs.deriving abstract]
type t = {
[#bs.optional]
id: float,
[#bs.optional]
text: string,
[#bs.optional]
todo: Todo.Attributes.t,
};
};
};
module Todo = {
[#bs.deriving abstract]
type t = {
[#bs.optional]
id: float,
[#bs.optional]
title: string,
[#bs.optional]
completed: bool,
[#bs.optional]
notes: array(Note.Attributes.t),
};
};
let todo = Todo.Attribute.t(~title="hello");
What if Note and Todo are in one file, an are in separated files?
I am not familliar with Reason but in OCaml, one would do this kind of stuff using mutually recursive module, as in the following minimal example.
Using mutally recursive requires to defines their module type:
module type NoteSig = sig
type t
end
module type TodoSig = sig
type t
end
and the actual modules:
module rec Note : NoteSig = struct
type t = {
todo: Todo.t
}
end
and Todo : TodoSig = struct
type t = {
notes: Note.t array
}
end
If you prefer both module to be in a separate file, you can do pretty much the same thing using functors (still using the module signatures, let's say in a file sig.ml):
a.ml:
module Note (T:Sig.TodoSig) = struct
type t = {
todo: T.t
}
end
b.ml:
module Todo (N:Sig.NoteSig) = struct
type t = {
notes: N.t array
}
end
You can now instanciate your modules in an other file :
c.ml:
module rec NoteImpl = (A.Note(TodoImpl):NoteSig)
and TodoImpl = (B.Todo(NoteImpl):TodoSig)
I can only suppose there is a way to to do the same thing in Reason, probably by adding a lot of brackets everywhere. Hope it helps.
Related
I have two modules, Graph and Game, which are parametrized by other modules. They also contain functions f and g which cause typechecking problems when I use them in a testing module. I left out lots of the code that is not important for this problem.
Here is a Graph module that has some module AbstractUSet. AbstractUSet.t is used a lot in the original code. The function f shall later take another function and do some work. The problem is, that the other function comes from another module and has a different type.
module UTYPE = sig
type t
val compare : t -> t -> int
end
module type GRAPH = sig
module U : UTYPE
module AbstractUSet : Set.S
val f : (AbstractUSet.t -> AbstractUSet.t) -> AbstractUSet.t -> AbstractUSet.t
end
module Graph (UA : UTYPE) : (GRAPH with module U=UA) = struct
module U=UA
module AbstractUSet = Set.Make(struct type t=U.t let compare=U.compare end)
let f g uset = g uset
end
The other module is the Game module. It does lots of things with AbstractVSet.t. It contains the function g that shall later be input for the function f from the Graph module.
module type GAME_PIECE = sig
type t
val compare : t -> t -> int
end
module type GAME = sig
module P : GAME_PIECE
module AbstractVSet : Set.S
val g : AbstractVSet.t -> AbstractVSet.t
end
module GameInstance (NA : GAME_PIECE) : (GAME with module P=NA) = struct
module P = NA
module AbstractVSet = Set.Make(struct type t=P.t let compare=P.compare end)
let g vset = vset
end
And this is my module for testing. In the very end, both UTYPE and GAME_PIECE are the same, but I can't make that clear to OCaml. I've commented the lines that don't typecheck. The compiler says there are clashes between MyGame.AbstractVSet.t and MyGraph.AbstractUSet.t.
module TestGame = struct
include(Game(struct type t=string let compare=compare end))
end
module TestGraph = struct
include(Graph(struct type t=string let compare=compare end))
end
module Test = struct
module MyGame = TestGame
module MyGraph = TestGraph
let stringlist = ["a";"b"]
let uset = MyGraph.uset_from_ulist stringlist // works fine
let vset = MyGame.vset_from_vlist stringlist // works fine
let result = MyGraph.f (MyGame.g) vset // does not typecheck!
end
If you ask, why I'm using so many modules: The project is a lot bigger than this code extract, and it is intended to be like this ;)
Can anyone help me how I can make it clear to the OCaml compiler that both UTYPE and GAME_PIECE are the same in the Test module??
Thanks a lot for your help!!!
The first issue is that your abstract set modules are different: the result of two functor applications in OCaml are only equals if the functor applications are applied to exactly the same named modules. For instance, in
module A = struct type t = int end
module F(X:sig type t end) = struct type t end
module FA = F(A)
module B = A
module FA' = F(B)
module C = F(struct type t end)
The types FA.t and Fa'.t are the same
let f (x:FA.t): FA'.t = x
But the types C.t and FA.t are different:
let f (x:C.t): FA'.t = x
Error: This expression has type C.t but an expression was expected of type
FA'.t
But this part can be fixed by not using anonymous structure when they are unnecessary:
module Graph (UA : UTYPE) : (GRAPH with module U=UA) = struct
module U=UA
module AbstractUSet = Set.Make(U)
let f g uset = g uset
end
Then, you are left with the "problem" that Game(M).AbstractUSet and
Graph(M).AbstractUSet defines two distinct types. (Note that this probably the right behavior outside of tests). For the test, one option is to simply expose the information that those modules are the result of functor applications. For instance, one can redefine the GAME module type (and GameInstance functor) to:
module type GAME = sig
type set
module P : GAME_PIECE
module AbstractVSet: Set.S with type t = set
val g : AbstractVSet.t -> AbstractVSet.t
end
module GameInstance (NA : GAME_PIECE) :
(GAME with type set:= Set.Make(NA).t and module P=NA) = struct
module P = NA
module AbstractVSet = Set.Make(NA)
let g vset = vset
end
Here, we have ketp the information that GameInstance(M).AbstractVSet.t is the
same type as Set.Make(M).t.
Combined wit the same operation on the graph part:
module type GRAPH = sig
type set
module U : UTYPE
module AbstractUSet : Set.S with type t = set
val f : (AbstractUSet.t -> AbstractUSet.t) -> AbstractUSet.t -> AbstractUSet.t
end
module Graph (UA : UTYPE) :
(GRAPH with type set := Set.Make(UA).t and module U=UA) = struct
module U=UA
module AbstractUSet = Set.Make(UA)
let f g uset = g uset
end
we are preserving enough type information to keep the equality for the test:
module TestGame = GameInstance(String)
module TestGraph = Graph(String)
module Test = struct
module MyGame = TestGame
module MyGraph = TestGraph
let result vset = MyGraph.f (MyGame.g) vset (* does typecheck *)
end
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
I don't understand why OCaml is not able to figure out that there is no room for confusion here: anint below can't be other one but A's.
module A = struct
type test = Graphics.status
end
module type ASIG = sig
type test = A.test
val atest : test
end
module Func (H : ASIG) = struct
let _ = let open H in atest.key
end
However, it raises
Warning 40: key was selected from type Graphics.status.
It is not visible in the current scope, and will not
be selected if the type becomes unknown.
How can I tell it "it's fine" without disabling the warning?
I'm aware I can solve it by opening A. However, if H defines its own functions and types similar---but not equal---to A, then it will have unnecessary clashes. I also know I can duplicate the definition, but that defeats the purpose of type aliasing, and involves lots of unnecessary code duplication. Perhaps there is no solution, but I wonder why OCaml is so blind dumb on this one: type alias should mean also constructor and record fields alias, shouldn't it?
You can simply open the the module defining the original type locally when referring to the field key as in the following:
module A = struct
type test = Graphics.status
end
module type ASIG = sig
type test = A.test
val atest : test
end
module Func (H : ASIG) = struct
let _ = let open H in atest.Graphics.key
end
Or if you need to refer to several fields :
let _ = let open H in Graphics.(atest.key, atest.button)
Well, this happens because the module signature ASIG needs to look the definition of type test for the implementation of A. This often causes problems with visibility of the types, and sometimes require duplication of type definitions, where the contract satisfies the implementation instead of referring to it.
How can we fix this warning? In ASIG, instead of defining type test = A.test, we need to explicitly do type test = { anint: int }as we did in the implementation, so:
module ASIG = sig
type test = { anint: int }
val atest : test
end
module A = struct
type test = { anint: int }
end
module Func (H : ASIG) = struct
let _ = let open H in atest.anint
end
The H module would not be able to view anintin its scope, otherwise, because the signature has a type (contract) that links to the implementation. It is also a core concept of OCaml philosophy isolating signatures and implementations and avoiding signatures depending upon implementations.
I have defined an interface A to be used by several functors, and notably by MyFunctor :
module type A = sig
val basic_func: ...
val complex_func: ...
end
module MyFunctor :
functor (SomeA : A) ->
struct
...
let complex_impl params =
...
(* Here I call 'basic_func' from SomeA *)
SomeA.basic_func ...
...
end
Now I want to define a module B with implements the interface A. In particular, the implementation of complex_func should use basic_func through complex_impl in MyFunctor :
module B = struct
let basic_func = ...
let complex_func ... =
let module Impl = MyFunctor(B) in
Impl.complex_impl ...
end
However, this code doesn't compile as B is not fully declared in the context of MyFunctor(B). Obviously B depends on MyFunctor(B), which itself depends on B, so I tried to use the rec keyword on module B, but it didn't work out.
So, is it possible to do something like this ? It would be useful as I have several modules B_1, ..., B_n that use the same implementation of B_k.complex_func in terms of B_k.basic_func.
Or is there a better pattern for my problem ? I know that I can declare complex_impl as a regular function taking basic_func as a parameter, without using a functor at all :
let complex_impl basic_func params =
...
basic_func ...
...
But in my case complex_impl uses many basic functions of A, and I think that the paradigm of functors is clearer and less error-prone.
Edit : I followed this answer, but in fact, A uses some type t that is specialized in B :
module type A = sig
type t
val basic_func: t -> unit
val complex_func: t -> unit
end
module MyFunctor :
functor (SomeA : A) ->
struct
let complex_impl (x : SomeA.t) =
SomeA.basic_func x
...
end
module rec B : A = struct
type t = int
val basic_func (x : t) = ...
val complex_func (x : t) =
let module Impl = MyFunctor(B) in
Impl.complex_impl x
end
And now I get the error (for x at line Impl.complex_impl x) :
This expression has type t = int but an expression was expected of type B.t
Edit 2 : I solved this second problem with the following code :
module rec B :
A with type t = int
= struct
type t = int
...
end
You can use recursive modules just like you'd write recursive let bindings
module type A = sig
val basic_func : unit -> int
val complex_func : unit -> int
end
module MyFunctor =
functor (SomeA : A) ->
struct
let complex_impl = SomeA.basic_func
end
module rec B : A = struct
let basic_func () = 0
let complex_func () =
let module Impl = MyFunctor(B) in
Impl.complex_impl ()
end
Note (a) the module rec bit in the definition of B and (b) that I am required to provide a module signature for a recursive module definition.
# B.basic_func ();;
- : int = 0
# B.complex_func ();;
- : int = 0
There's a small caveat, however, in that this only works because the signature A has only values which are function types. It is thus known as a "safe module". If basic_func and complex_func were values instead of function types then it would fail upon compilation
Error: Cannot safely evaluate the definition
of the recursively-defined module B
I want to create a function object, which also has some properties held on it. For example in JavaScript I would do:
var f = function() { }
f.someValue = 3;
Now in TypeScript I can describe the type of this as:
var f: { (): any; someValue: number; };
However I can't actually build it, without requiring a cast. Such as:
var f: { (): any; someValue: number; } =
<{ (): any; someValue: number; }>(
function() { }
);
f.someValue = 3;
How would you build this without a cast?
Update: This answer was the best solution in earlier versions of TypeScript, but there are better options available in newer versions (see other answers).
The accepted answer works and might be required in some situations, but have the downside of providing no type safety for building up the object. This technique will at least throw a type error if you attempt to add an undefined property.
interface F { (): any; someValue: number; }
var f = <F>function () { }
f.someValue = 3
// type error
f.notDeclard = 3
This is easily achievable now (typescript 2.x) with Object.assign(target, source)
example:
The magic here is that Object.assign<T, U>(t: T, u: U) is typed to return the intersection T & U.
Enforcing that this resolves to a known interface is also straight-forward. For example:
interface Foo {
(a: number, b: string): string[];
foo: string;
}
let method: Foo = Object.assign(
(a: number, b: string) => { return a * a; },
{ foo: 10 }
);
which errors due to incompatible typing:
Error: foo:number not assignable to foo:string
Error: number not assignable to string[] (return type)
caveat: you may need to polyfill Object.assign if targeting older browsers.
TypeScript is designed to handle this case through declaration merging:
you may also be familiar with JavaScript practice of creating a function and then extending the function further by adding properties onto the function. TypeScript uses declaration merging to build up definitions like this in a type-safe way.
Declaration merging lets us say that something is both a function and a namespace (internal module):
function f() { }
namespace f {
export var someValue = 3;
}
This preserves typing and lets us write both f() and f.someValue. When writing a .d.ts file for existing JavaScript code, use declare:
declare function f(): void;
declare namespace f {
export var someValue: number;
}
Adding properties to functions is often a confusing or unexpected pattern in TypeScript, so try to avoid it, but it can be necessary when using or converting older JS code. This is one of the only times it would be appropriate to mix internal modules (namespaces) with external.
So if the requirement is to simply build and assign that function to "f" without a cast, here is a possible solution:
var f: { (): any; someValue: number; };
f = (() => {
var _f : any = function () { };
_f.someValue = 3;
return _f;
})();
Essentially, it uses a self executing function literal to "construct" an object that will match that signature before the assignment is done. The only weirdness is that the inner declaration of the function needs to be of type 'any', otherwise the compiler cries that you're assigning to a property which does not exist on the object yet.
EDIT: Simplified the code a bit.
Old question, but for versions of TypeScript starting with 3.1, you can simply do the property assignment as you would in plain JS, as long as you use a function declaration or the const keyword for your variable:
function f () {}
f.someValue = 3; // fine
const g = function () {};
g.someValue = 3; // also fine
var h = function () {};
h.someValue = 3; // Error: "Property 'someValue' does not exist on type '() => void'"
Reference and online example.
As a shortcut, you can dynamically assign the object value using the ['property'] accessor:
var f = function() { }
f['someValue'] = 3;
This bypasses the type checking. However, it is pretty safe because you have to intentionally access the property the same way:
var val = f.someValue; // This won't work
var val = f['someValue']; // Yeah, I meant to do that
However, if you really want the type checking for the property value, this won't work.
I can't say that it's very straightforward but it's definitely possible:
interface Optional {
<T>(value?: T): OptionalMonad<T>;
empty(): OptionalMonad<any>;
}
const Optional = (<T>(value?: T) => OptionalCreator(value)) as Optional;
Optional.empty = () => OptionalCreator();
if you got curious this is from a gist of mine with the TypeScript/JavaScript version of Optional
An updated answer: since the addition of intersection types via &, it is possible to "merge" two inferred types on the fly.
Here's a general helper that reads the properties of some object from and copies them over an object onto. It returns the same object onto but with a new type that includes both sets of properties, so correctly describing the runtime behaviour:
function merge<T1, T2>(onto: T1, from: T2): T1 & T2 {
Object.keys(from).forEach(key => onto[key] = from[key]);
return onto as T1 & T2;
}
This low-level helper does still perform a type-assertion, but it is type-safe by design. With this helper in place, we have an operator that we can use to solve the OP's problem with full type safety:
interface Foo {
(message: string): void;
bar(count: number): void;
}
const foo: Foo = merge(
(message: string) => console.log(`message is ${message}`), {
bar(count: number) {
console.log(`bar was passed ${count}`)
}
}
);
Click here to try it out in the TypeScript Playground. Note that we have constrained foo to be of type Foo, so the result of merge has to be a complete Foo. So if you rename bar to bad then you get a type error.
NB There is still one type hole here, however. TypeScript doesn't provide a way to constrain a type parameter to be "not a function". So you could get confused and pass your function as the second argument to merge, and that wouldn't work. So until this can be declared, we have to catch it at runtime:
function merge<T1, T2>(onto: T1, from: T2): T1 & T2 {
if (typeof from !== "object" || from instanceof Array) {
throw new Error("merge: 'from' must be an ordinary object");
}
Object.keys(from).forEach(key => onto[key] = from[key]);
return onto as T1 & T2;
}
This departs from strong typing, but you can do
var f: any = function() { }
f.someValue = 3;
if you are trying to get around oppressive strong typing like I was when I found this question. Sadly this is a case TypeScript fails on perfectly valid JavaScript so you have to you tell TypeScript to back off.
"You JavaScript is perfectly valid TypeScript" evaluates to false. (Note: using 0.95)