How to write reasonml binding for a union type - ocaml

I am trying to write bindings for https://github.com/oblador/react-native-keychain/blob/master/typings/react-native-keychain.d.ts#L76
getGenericPassword returns false if an error, else an object (credentials). I am not sure this union type can be represented in reason, but a better API would be the result an option (option(credentials)). But, how can I convert Promise<boolean | credentials> -> Js.Promise.t(option(credentials)) in the binding file. Below is a template.
Thanks for your help.
[#bs.deriving abstract]
type credentials = {
service: string,
username: string,
password: string,
};
/* TODO convert the actual return value
Js.Promise.t(option(credentials)) to more reason type
Js.Promise.t(option(credentials)) */
[#bs.module "react-native-keychain"] [#bs.scope "default"]
external getGenericPassword: unit => Js.Promise.t(option(credentials)) = "";

You can use Js.Types.classify to get the runtime type of a value.
type maybeCredentials;
[#bs.module "react-native-keychain"] [#bs.scope "default"]
external getGenericPassword: unit => Js.Promise.t(maybeCredentials) = "";
let getGenericPassword: unit => Js.Promise.t(option(credentials)) =
() =>
Js.Promise.(
getGenericPassword()
|> then_(maybeCredentials =>
switch (Js.Types.classify(maybeCredentials)) {
| JSObject(obj) => resolve(Some(obj |> Obj.magic))
| _ => resolve(None)
}
)
);
Here maybeCredentials is defined and used as an intermediate type.
We then define a function with the same name as the binding, which will "shadow" the name and prevent the binding from being used directly in favour of our "override". However, within the override we're still able to use the binding.
We then call Js.Types.classify to get the runtime type of the returned value. If it is an object we use Obj.magic to cast the abstract obj_type to our credentials type (inferred from the return type of the function), and wrap it in an option. For any other type we return None.
By the way, this kind of "type" is called an untagged union. I've written down a few examples using different strategies for dealing with these, as both a producer and a consumer, in bucklescript-cookbook.

Related

Why NamedTuple of same types are not compatible?

Why NamedTuple of the same type are not compatible?
alias Data = NamedTuple(
title: String?
)
data : Data = { title: nil } # Explicitly specifying that
# it has ` : Data` type
proc = ->(data : Data){ p data }
proc.call data # And yet it says it's not
# of `Data` type
Error
Error: type must be NamedTuple(title: String | Nil), not NamedTuple(title: Nil)
Your assumption is incorrect: data : Data restricts the type of the local variable to Data (which is an alias for NamedTuple(title: String | Nil)). This type restriction does not affect the value assignment on the right hand side. The literal value {type: nil} is typed as NamedTuple(title: Nil). This type is compatible with the type restriction to Data, so it can be assigned to the variable.
This implicitly covariant type restriction does not apply with proc types. I'm not sure about the reasoning behind that. It seems that this should be able to work. So maybe it just needs to be implemented.
You can however explicitly cast NamedTuple(Nil) to NamedTuple(String | Nil):
alias Data = NamedTuple(
title: String?
)
data = { title: nil }.as(Data) # Cast named tuple to Data
proc = ->(data : Data){ p data }
proc.call data
However, it is usually not a good idea to work with named tuples as regular data types. They are only recommended for very specific use cases such as named arguments. Defining custom structs (for example using the record macro) is a better idea and gives you a more powerful and flexible data type.
I'd implement your example like this:
record Data,
title : String?
data = Data.new(title: nil)
proc = ->(data : Data){ p data }
proc.call data
This is a bug, please report it in the issue tracker. Thank you!

Crystal Lang: Can't infer the type of instance variable '#hash_value' of Rule

Here's my crystal code, in snippets, but I think it's all there:
# spec_helper.rb
def fixtures
rawhash = JSON.parse(File.read("spec/fixtures/state3.json"))
rules = rawhash["rules"]
id = rules.as_h.keys[0]
hash = rules[id]
return id, hash
end
# rule_spec.rb
key, hash = fixtures
rule = Rule.new(key, hash)
rule.array(["name"])[0].must_equal "RpsIphone"
# rule.rb
class Rule < HueResource
getter :detail, :on, :name, :lights
def initialize(key, hashvalue)
super(key, hashvalue)
#detail = "#{hashvalue["conditions"].length} conds => #{hashvalue["actions"].length} acts"
#state.merge! ({"on" => hash_value["status"], "name" => #name, "detail" => #detail})
gen_reskey("r")
end
...
end
# hue resource.rb
class HueResource
def initialize(key, hash_value)
#hash_value = hash_value.as_h
#lastupdated = #hash_value["state"]["lastupdated"]
#detail = hash_value["type"]
#name = hash_value["name"]
#state = { "key" => key, "lastupdated" => #lastupdated, "detail" => #detail, "name" => #name}
end
def gen_reskey(detail)
#state.merge!({ "id" => detail + #state["key"]})
end
end
And here's the error:
[Running] crystal "/Users/pitosalas/mydev/crystalplay/spec/rule_spec.cr"
Error in spec/rule_spec.cr:7: instantiating 'Rule.class#new(String, JSON::Any)'
rule = Rule.new(key, hash)
[32;1m^~~[0m
in src/rule.cr:7: instantiating 'super(String, JSON::Any)'
super(key, hashvalue)
[32;1m^~~~~[0m
in src/hue_resource.cr:3: [1mCan't infer the type of instance variable '#hash_value' of Rule
The type of a instance variable, if not declared explicitly with
`#hash_value : Type`, is inferred from assignments to it across
the whole program.
Now it seems to me that in the constructors, #hash_value is assigned to hash_value.as_h so it would know the type from there on.
Also feel free to point out Crystal stylistic or idiomatic comments!
The compiler can't infer ivar types from the return type of method calls (like hash_value.as_h). The reference of Type inference lists all rules where the compiler can infer ivar types.
Infering the type from method calls is probably not impossible, but more complicated. It might come to the language at some point, but for now you'll have to use an explicit type annotation such as #hash_value : Hash(JSON::Any, JSON::Any).

OCaml - confusion from type alias (warning 40)

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.

How to bind a whole module as a function?

I'm playing with reason, and I wanted to try to do the FFI for debug in order to learn. I have this code
module Instance = {
type t;
external t : t = "" [##bs.module];
};
module Debug = {
type t;
external createDebug : string => Instance.t = "debug" [##bs.module];
};
and I'm trying to use it like this
open Debug;
let instance = Debug.createDebug "app";
instance "Hello World !!!";
but I get the following error
Error: This expression has type Debug.Instance.t
This is not a function; it cannot be applied.
Wasn't instance supposed to be bind to a function? I also tried with
module Instance = {
type t;
external write : string => unit = "" [##bs.send];
};
and
open Debug;
let instance = Debug.createDebug "app";
instance.write "Hello World !!!";
but I get
Error: Unbound record field write
What am I missing?
The createDebug function, according to your declaration, returns a value of type Instance.t. It is an abstract value, in a sense that nothing is known about its implementation, and you can only use it via its interface. The interface of a type is, basically, all values (functions) that allow you to manipulate a value of this type. In your case, we can find only two such values - the Instance.t value and Debug.createDebug function. Both can be used, according to your own declarations, to create such value. No functions are provided to use it.
Probably, you have some misunderstanding of what module is. It is not an object per se, but rather a namespace. It is like a file in file.
Your second example justifies that you're thinking of modules, as they are a sort of runtime objects or records. But, they are just static structures that are used to organize big programs into hierarchical namespaces.
What you're trying to use is actually a record:
type debug = { write : string => unit }
let create_debug service => {
write: fun msg => print_endline (service ^ ": " ^ msg)
}
let debug = create_debug "server"
debug.write "started"
Will yield:
server: started

Testing interfaces with foq

I am trying to use Foq to testing an interface with Foq.
So far, all examples I have seen for this have been relatively simple, such as the following:
let users = [|{ID = 1; pass = true};{ID = 2; pass= false}|]
type IFoo =
abstract member Bar: int -> bool
//tests with Foq
let dataAccess =
Mock<IFoo>()
.Setup(fun x-> <# x.Bar(users.[0].ID) #>).Returns(users.[0].pass)
.Setup(fun x-> <# x.Bar(users.[1].ID) #>).Returns(users.[1].pass)
.Create()
The examples have been sourced from 'Testing with F# - Mikael Lundin'
I have also researched this through a bit of googling (this link was helpful - http://trelford.com/blog/post/Foq.aspx)
However, the real Interfaces I want to test are the following:
type IParameters =
abstract member ParameterDate : int->string->DateTime
type IDataSource =
abstract member MortParameters: IParameters
I have tried a number of different ways to test these (e.g. defining a function with a signature of int->string to be used as the input to the setup. Alternatively, having the return value as a string->DateTime and the Setup as just an integer.
My question is really the following: When testing interfaces using Foq, how can I extend the testing to interfaces with function signatures of any general length (e.g. a->b->c->d->e etc.)
Since ParameterDate a property with a function type, you could just set it up as a property that returns a lambda value. See an example of property set-up in Foq. This should be easy to modify for your case:
let instance =
Mock<System.Collections.IList>()
.Setup(fun x -> <# x.Count #>).Returns(1)
.Create()
However, I guess you would lose the ability to have a strict mock with fixed expectations on the function inputs.
To enforce only expected inputs for the function returned by the mock property you could provide a function like this:
fun i s ->
match i, s with
| 1, "" -> DateTime.Now
| _ -> failwith "Invalid mock input"
I would probably stop here, but if you're working with code where you need to verify a function was called, as opposed to just ensuring you get the correct output, you could add a helper like this:
type Verifiable<'a, 'b> (f : 'a -> 'b) =
let called = ref false
member this.Func x =
called := true
f x
member this.Verify() =
if not called.Value then failwith "Mock function was not called"
And here's how you would use it:
let parameterDateMock =
fun i s ->
match i, s with
| 1, "" -> DateTime.Now
| _ -> failwith "Unexpected mock input"
|> Verifiable
let parameters =
{ new IParameters with member this.ParameterDate i s = parameterDateMock.Func i s }
parameters.ParameterDate 1 ""
parameterDateMock.Verify()
Caveat: This only verifies the function was called with at least one parameter. It may have returned another function by currying and not actually run the code in the mock function body. To get around that you'd need a variation of the Verifiable class for every function arity and use the right one in each case.