how to make these functions generic, in F#? - struct

I have these two functions:
// load from cache
let private loadFromCacheAsync filespec =
async {
let! bytes = File.ReadAllBytesAsync(filespec) |> Async.AwaitTask
let result =
use pBytes = fixed bytes
let sourceSpan = Span<byte>(NativePtr.toVoidPtr pBytes, bytes.Length)
MemoryMarshal.Cast<byte, ShortTradeData>(sourceSpan).ToArray()
return (result |> Array.map (fun x -> x.ToTradeData()))
}
// save to cache
let private saveToCacheAsync filespec (data: TradeData array) =
Directory.CreateDirectory cacheFolder |> ignore
let sizeStruct = sizeof<ShortTradeData>
let smallData = data |> Array.map ShortTradeData.FromTradeData
use ptr = fixed smallData
let nativeSpan = Span<byte>(NativePtr.toVoidPtr ptr, data.Length * sizeStruct).ToArray()
File.WriteAllBytesAsync(filespec, nativeSpan) |> Async.AwaitTask
and I'm trying to make them generic:
// load from cache
let private loadFromCacheAsync<'a> filespec =
async {
let! bytes = File.ReadAllBytesAsync(filespec) |> Async.AwaitTask
let result =
use pBytes = fixed bytes
let sourceSpan = Span<byte>(NativePtr.toVoidPtr pBytes, bytes.Length)
MemoryMarshal.Cast<byte, 'a>(sourceSpan).ToArray()
return result
}
// save to cache
let private saveToCacheAsync<'a> filespec (data: 'a array) =
Directory.CreateDirectory cacheFolder |> ignore
let sizeStruct = sizeof<'a>
use ptr = fixed data
let nativeSpan = Span<byte>(NativePtr.toVoidPtr ptr, data.Length * sizeStruct).ToArray()
File.WriteAllBytesAsync(filespec, nativeSpan) |> Async.AwaitTask
the first one fails to compile with:
"No overloads known for method Cast"
and the second one fails to compile with:
"A type parameter is missing a constraint 'when 'a: unmanaged'
so I can make the second one compile by changing the function:
let private saveToCacheAsync<'a when 'a: unmanaged> filespec (data: 'a array) =
but I assumed that "when 'a: struct" would make more sense. Upon reading the doc, it looks like unmanaged works for structs with primitive (unmanaged) types... still don't know why struct doesn't work.
But for the first function, I don't have any idea what should be done to fix it.
The full error message is:
DataCache.fs(28, 17): [FS0041] No overloads match for method 'Cast'.
Known type of argument: Span<byte>
Available overloads:
- MemoryMarshal.Cast<'TFrom,'TTo when 'TFrom: (new: unit -> 'TFrom) and 'TFrom: struct and 'TFrom :> ValueType and 'TTo: (new: unit -> 'TTo) and 'TTo: struct and 'TTo :> ValueType>(span: ReadOnlySpan<'TFrom>) : ReadOnlySpan<'TTo>
- MemoryMarshal.Cast<'TFrom,'TTo when 'TFrom: (new: unit -> 'TFrom) and 'TFrom: struct and 'TFrom :> ValueType and 'TTo: (new: unit -> 'TTo) and 'TTo: struct and 'TTo :> ValueType>(span: Span<'TFrom>) : Span<'TTo>
and if I look at the types it takes:
'TTo when 'TFrom: (new: unit -> 'TFrom)
'TFrom: struct
'TFrom :> ValueType
'TTo: (new: unit -> 'TTo)
'TTo: struct
'TTo :> ValueType
we care about TTo here:
'TTo when 'TFrom: (new: unit -> 'TFrom)
'TTo: (new: unit -> 'TTo)
'TTo: struct
'TTo :> ValueType
I still don't get it: it looks like it needs to be a struct, and can be cast as a value type (struct then?) and have an empty constructor? I don't understand the first line.

Since loadFromCacheAsync's "from" type parameter is always byte, you only need three constraints on its "to" parameter, which you've called 'a:
'a: (new: unit -> 'a)
'a: struct
'a :> System.ValueType
The last two do seem redundant, but I assume this is just an artifact of .NET's underlying requirements.
The resulting signature for loadFromCacheAsync is:
let private loadFromCacheAsync<'a when 'a: (new: unit -> 'a) and 'a: struct and 'a :> ValueType> filespec =

Related

Rust adding associated type with u32

I have an associated type MyType.
This type is going to be an unsigned integer, but I use it because the size of the unsigned integer required for this variable is maybe going to change in the future. So MyType is going to be one of: u32, u64, u128.
So MyType will look like this when defined: MyType = u32 (of course it may not be u32).
In my code, I need to increment this variable of type MyType by one.
so I have to do this: let n: MyType = v + 1, where v is the type of MyType.
How can I do this, what trait restrictions should MyType have?
I would want something like this: type MyType: UnsignedInt, but the problem is there is no number trait in rust as far as I have seen.
Your description is very vague and it would be much easier if you added a code example, but deriving from the word associated type I tried to reconstruct a minimal example:
trait Incrementor {
type MyType;
fn increment(&self, value: Self::MyType) -> Self::MyType {
value + 1
}
}
struct U32Incrementor;
impl Incrementor for U32Incrementor {
type MyType = u32;
}
fn main() {
let incrementor = U32Incrementor;
println!("{}", incrementor.increment(10));
}
error[E0369]: cannot add `{integer}` to `<Self as Incrementor>::MyType`
--> src/main.rs:5:15
|
5 | value + 1
| ----- ^ - {integer}
| |
| <Self as Incrementor>::MyType
|
= note: the trait `std::ops::Add` is not implemented for `<Self as Incrementor>::MyType`
Is that about the problem you are having?
If yes, does this help?
use num_traits::{FromPrimitive, One, Unsigned};
trait Incrementor {
type MyType: Unsigned + FromPrimitive;
fn increment(&self, value: Self::MyType) -> Self::MyType {
value + Self::MyType::one()
}
fn increment_ten(&self, value: Self::MyType) -> Self::MyType {
value + Self::MyType::from_u8(10).unwrap()
}
}
struct U32Incrementor;
impl Incrementor for U32Incrementor {
type MyType = u32;
}
fn main() {
let incrementor = U32Incrementor;
println!("{}", incrementor.increment(10));
println!("{}", incrementor.increment_ten(10));
}
11
20
It's based on the excellent num_traits crate.
The + operator behavior is specified by the trait std::ops::Add. This trait is generic over its output type, so if you want for example MyType to have the semantics MyType + MyType = MyType you can write:
trait MyTrait {
type MyType: std::ops::Add<Output = Self::MyType>;
}
All integers will implement this. If you need additional operators you can use the traits from std::ops, but with multiple bounds this can become tedious. The crate num-traits can help you with pre-declared traits that has all required ops and more. For example the trait NumOps specify all arithmetic operators, and there are more traits such as Num that includes equality and zero/one or PrimInt that specifies basically every operation or method integers in Rust have.

Why does Rust allow multidefinition of identifiers?

Consider a mini example
fn main() {
let a = Vec::from([1, 2, 3]);
let Vec = 1.;
println!("{}", Vec);
let b = Vec::from([1, 2, 3]);
let c: Vec<i32> = Vec::new();
}
where I redefine Vec as a f64 variable. Why does Rust allow for such operation?
The code above will print 1. and suprisingly after redefining Vec as a number, the lines let b = Vec::new(); work as well! So Vec exists both as an f64 and a Vec struct? In many other languages, I think they will throw errors.
Suppose that both f64 and Vec have a method test() implemented, if I call Vec.test(), does it excute test() from f64 or Vec?
Types and variables are distinguished by syntax, so using the same identifier for both is harmless and therefore allowed. While that's slightly unusual, it's not unheard of - for example, this is valid Java:
public class HelloWorld {
public static void main(String []args) {
int hello = 1;
hello(hello); // <-- wat
}
static void hello(int n) {
System.out.println("Hello " + n);
}
}
Note that such use of identifier will inevitably trigger a compilation warning because variables and types use different case conventions.
Suppose that both f64 and Vec have a method test() implemented, if I call Vec.test(), does it execute test() from f64 or Vec?
It executes the one from f64.
There is no ambiguity because Vec as type and Vec as value of type f64 are completely different things. To call the method defined by the Vec type through the Vec type, you'd have to call Vec::test(...). To call the f64 method through the Vec variable you'd have to call Vec.test(...) or f64::test(&Vec, ...) - no ambiguity either way. (And that's assuming f64::test() takes &self; if it didn't, you couldn't invoke it through instance in the first place, so there'd be even less confusion.)

How to create an F# struct with a function member and a default public constructor?

I need to create a struct type for passing to an external class that is not under my control. That class requires that my struct type has a public default constructor. I need it to have a function type as a member.
The following produces error FS0001: A generic construct requires that the type 'MyStruct' have a public default constructor:
[<Struct>]
type MyStruct =
val callBack: unit -> unit
new(cb: unit -> unit) = { callBack = cb }
type ExternalClass<'T when 'T : (new : unit -> 'T) and 'T : struct> () =
member val something = new 'T()
let c = new ExternalClass<MyStruct>()
This works fine if the type of the member is changed from unit -> unit to int.
I've tried using a DefaultValue attribute, which according to the docs should work fine on a function member, but this produces two errors: error FS0765: Extraneous fields have been given values and error FS0696: This is not a valid object construction expression. Explicit object constructors must either call an alternate constructor or initialize all fields of the object and specify a call to a super class constructor.
How can I create a suitable type to meet the external class's constraint?
The problem here is that the type unit -> unit does not have a default value. Here's a shorter repro:
[<Struct>]
type MyStruct =
val callBack: unit -> unit
let s = MyStruct()
You get an error on the last line saying: The default, zero-initializing constructor of a struct type may only be used if all the fields of the struct type admit default initialization
The type unit -> unit doesn't admit default initialization. It must have a value of function type, and there is no such thing as "default" function value.
This is how structs in .NET work: every struct always has a default constructor, and the programmer doesn't get to implement it. Instead, the runtime initializes all fields with their default values. The idea behind this is to make allocating arrays or structs very cheap: you just zero out a memory block, and voila!
So by this logic, your callBack field must be zero-outable, but it can't be, because in F# function-typed variables can't be null.
It works fine with int, because int does indeed have a default value of zero.
Now, a "good" solution would depend on what it is you're actually trying to do. But in the absence of that information, I can suggest a couple of local workarounds.
First option - make the field have type obj (so its default value would be null) and provide a safe-ish accessor that would return an option:
[<Struct>]
type MyStruct =
val private callBack: obj
member this.Callback with get() = this.callBack |> Option.ofObj |> Option.map (fun o -> o :?> (unit -> unit))
new(cb: unit -> unit) = { callBack = cb }
The Callback accessor property would then return a (unit -> unit) option, which would be Some if the function was initialized or None if it wasn't:
> MyStruct().Callback;;
val it : (unit -> unit) option = None
> MyStruct(fun() -> ()).Callback;;
val it : (unit -> unit) option = Some <fun:it#10>
Second option - wrap the callback in a nullable type:
[<AllowNullLiteral>]
type ACallback(cb : unit -> unit) =
member val Callback = cb with get
[<Struct>]
type MyStruct =
val callBack: ACallback
new(cb: unit -> unit) = { callBack = ACallback cb }
Then:
> MyStruct().callBack;;
val it : ACallback = <null>
> MyStruct(fun() -> ()).callBack;;
val it : ACallback = FSI_0006+ACallback {Callback = <fun:it#30-1>;}
This (arguably) provides a bit more type safety at the expense of an extra allocation.
Plus, there is a possibility of getting a null, but if that's a problem, you can wrap that in an option-typed accessor too:
[<Struct>]
type MyStruct =
val private callBack: ACallback
member this.Callback with get() = this.callBack |> Option.ofObj |> Option.map (fun c -> c.Callback)
new(cb: unit -> unit) = { callBack = ACallback cb }
> MyStruct().Callback;;
val it : (unit -> unit) option = None
> MyStruct(fun() -> ()).Callback;;
val it : (unit -> unit) option = Some <fun:it#38-2>

Calling a function which takes a closure twice with different closures

As a project for learning rust, I am writing a program which can parse sgf files (a format for storing go games, and technically also other games). Currently the program is supposed to parse strings of the type (this is just an exampel) ";B[ab]B[cd]W[ef]B[gh]" into [Black((0,1)),Black((2,3,)),White((4,5)),Black((6,7))]
For this I am using the parser-combinators library.
I have run into the following error:
main.rs:44:15: 44:39 error: can't infer the "kind" of the closure; explicitly annotate it; e.g. `|&:| {}` [E0187]
main.rs:44 pmove().map(|m| {Property::White(m)})
^~~~~~~~~~~~~~~~~~~~~~~~
main.rs:44:15: 44:39 error: mismatched types:
expected `closure[main.rs:39:15: 39:39]`,
found `closure[main.rs:44:15: 44:39]`
(expected closure,
found a different closure) [E0308]
main.rs:44 pmove().map(|m| {Property::White(m)})
^~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to 2 previous errors
Could not compile `go`.
The function in question is below. I am completely new to rust, so I can't really isolate the problem further or recreate it in a context without the parser-combinators library (might even have something to do with that library?).
fn parse_go_sgf(input: &str) -> Vec<Property> {
let alphabetic = |&:| {parser::satisfy(|c| {c.is_alphabetic()})};
let prop_value = |&: ident, value_type| {
parser::spaces().with(ident).with(parser::spaces()).with(
parser::between(
parser::satisfy(|c| c == '['),
parser::satisfy(|c| c == ']'),
value_type
)
)
};
let pmove = |&:| {
alphabetic().and(alphabetic())
.map(|a| {to_coord(a.0, a.1)})
};
let pblack = prop_value(
parser::string("B"),
pmove().map(|m| {Property::Black(m)}) //This is where I am first calling the map function.
);
let pwhite = prop_value(
parser::string("W"),
pmove().map(|m| {Property::White(m)}) //This is where the compiler complains
);
let pproperty = parser::try(pblack).or(pwhite);
let mut pnode = parser::spaces()
.with(parser::string(";"))
.with(parser::many(pproperty));
match pnode.parse(input) {
Ok((value, _)) => value,
Err(err) => {
println!("{}",err);
vec!(Property::Unkown)
}
}
}
So I am guessing this has something to do with closures all having different types. But in other cases it seems possible to call the same function with different closures. For example
let greater_than_forty_two = range(0, 100)
.find(|x| *x > 42);
let greater_than_forty_three = range(0, 100)
.find(|x| *x > 43);
Seems to work just fine.
So what is going on in my case that is different.
Also, as I am just learning, any general comments on the code are also welcome.
Unfortunately, you stumbled upon one of the rough edges in the Rust type system (which is, given the closure-heavy nature of parser-combinators, not really unexpected).
Here is a simplified example of your problem:
fn main() {
fn call_closure_fun<F: Fn(usize)>(f: F) { f(12) } // 1
fn print_int(prefix: &str, i: usize) { println!("{}: {}", prefix, i) }
let call_closure = |&: closure| call_closure_fun(closure); // 2
call_closure(|&: i| print_int("first", i)); // 3.1
call_closure(|&: i| print_int("second", i)); // 3.2
}
It gives exactly the same error as your code:
test.rs:8:18: 8:47 error: mismatched types:
expected `closure[test.rs:7:18: 7:46]`,
found `closure[test.rs:8:18: 8:47]`
(expected closure,
found a different closure) [E0308]
test.rs:8 call_closure(|&: i| print_int("second", i));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
We have (referenced in the comments in the code):
a function which accepts a closure of some concrete form;
a closure which calls a function (1) with its own argument;
two invocations of closure (1), passing different closures each time.
Rust closures are unboxed. It means that for each closure the compiler generates a fresh type which implements one of closure traits (Fn, FnMut, FnOnce). These types are anonymous - they don't have a name you can write out. All you know is that these types implement a certain trait.
Rust is a strongly- and statically-typed language: the compiler must know exact type of each variable and each parameter at the compile time. Consequently it has to assign types for every parameter of every closure you write. But what type should closure argument of (2) have? Ideally, it should be some generic type, just like in (1): the closure should accept any type as long as it implements a trait. However, Rust closures can't be generic, and so there is no syntax to specify that. So Rust compiler does the most natural thing it can - it infers the type of closure argument based on the first use of call_closure, i.e. from 3.1 invocation - that is, it assigns the anonymous type of the closure in 3.1!
But this anonymous type is different from the anonymous type of the closure in 3.2: the only thing they have in common is that they both implement Fn(usize). And this is exactly what error is about.
The best solution would be to use functions instead of closures because functions can be generic. Unfortunately, you won't be able to do that either: your closures return structures which contain closures inside themselves, something like
pub struct Satisfy<I, Pred> { ... }
where Pred is later constrained to be Pred: FnMut(char) -> bool. Again, because closures have anonymous types, you can't specify them in type signatures, so you won't be able to write out the signature of such generic function.
In fact, the following does work (because I've extracted closures for parser::satisfy() calls to parameters):
fn prop_value<'r, I, P, L, R>(ident: I, value_type: P, l: L, r: R) -> pp::With<pp::With<pp::With<pp::Spaces<&'r str>, I>, pp::Spaces<&'r str>>, pp::Between<pp::Satisfy<&'r str, L>, pp::Satisfy<&'r str, R>, P>>
where I: Parser<Input=&'r str, Output=&'r str>,
P: Parser<Input=&'r str, Output=Property>,
L: Fn(char) -> bool,
R: Fn(char) -> bool {
parser::spaces().with(ident).with(parser::spaces()).with(
parser::between(
parser::satisfy(l),
parser::satisfy(r),
value_type
)
)
}
And you'd use it like this:
let pblack = prop_value(
parser::string("B"),
pmove().map(|&: m| Property::Black(m)),
|c| c == '[', |c| c == ']'
);
let pwhite = prop_value(
parser::string("W"),
pmove().map(|&: m| Property::White(m)),
|c| c == '[', |c| c == ']'
);
pp is introduced with use parser::parser as pp.
This does work, but it is really ugly - I had to use the compiler error output to actually determine the required return type. With the slightest change in the function it will have to be adjusted again. Ideally this is solved with unboxed abstract return types - there is a postponed RFC on them - but we're still not there yet.
As the author of parser-combinators I will just chime in on another way of solving this, without needing to use the compiler to generate the return type.
As each parser is basically just a function together with 2 associated types there are implementations for the Parser trait for all function types.
impl <I, O> Parser for fn (State<I>) -> ParseResult<O, I>
where I: Stream { ... }
pub struct FnParser<I, O, F>(F);
impl <I, O, F> Parser for FnParser<I, O, F>
where I: Stream, F: FnMut(State<I>) -> ParseResult<O, I> { ... }
These should all be replaced by a single trait and the FnParser type removed, once the orphan checking allows it. In the meantime we can use the FnParser type to create a parser from a closure.
Using these traits we can essentially hide the big parser type returned from in Vladimir Matveev's example.
fn prop_value<'r, I, P, L, R>(ident: I, value_type: P, l: L, r: R, input: State<&'r str>) -> ParseResult<Property, &'r str>
where I: Parser<Input=&'r str, Output=&'r str>,
P: Parser<Input=&'r str, Output=Property>,
L: Fn(char) -> bool,
R: Fn(char) -> bool {
parser::spaces().with(ident).with(parser::spaces()).with(
parser::between(
parser::satisfy(l),
parser::satisfy(r),
value_type
)
).parse_state(input)
}
And we can now construct the parser with this
let parser = FnParser(move |input| prop_value(ident, value_type, l, r, input));
And this is basically the best we can do at the moment using rust. Unboxed anonymous return types would make all of this significantly easier since complex return types would not be needed (nor created since the library itself could be written to utilize this, avoiding the complex types entirely).
Two facets of Rust's closures are causing your problem, one, closures cannot be generic, and two, each closure is its own type. Because closure's cannot be generic,prop_value's parameter value_type must be a specific type. Because each closure is a specific type, the closure you pass to prop_value in pwhite is a different type from the one in pblack. What the compiler does is conclude that the value_type must have the type of the closure in pblack, and when it gets to pwhite it finds a different closure, and gives an error.
Judging from your code sample, the simplest solution would probably be to make prop_value a generic fn - it doesn't look like it needs to be a closure. Alternatively, you could declare its parameter value_type to be a closure trait object, e.g. &Fn(...) -> .... Here is a simplifed example demonstrating these approaches:
fn higher_fn<F: Fn() -> bool>(f: &F) -> bool {
f()
}
let higher_closure = |&: f: &Fn() -> bool | { f() };
let closure1 = |&:| { true };
let closure2 = |&:| { false };
higher_fn(&closure1);
higher_fn(&closure2);
higher_closure(&closure1);
higher_closure(&closure2);
The existing answer(s) are good, but I wanted to share an even smaller example of the problem:
fn thing<F: FnOnce(T), T>(f: F) {}
fn main() {
let caller = |&: f| {thing(f)};
caller(|&: _| {});
caller(|&: _| {});
}
When we define caller, its signature is not fully fixed yet. When we call it the first time, type inference sets the input and output types. In this example, after the first call, caller will be required to take a closure with a specific type, the type of the first closure. This is because each and every closure has its own unique, anonymous type. When we call caller a second time, the second closure's (unique, anonymous) type doesn't fit!
As #wingedsubmariner points out, there's no way to create closures with generic types. If we had hypothetical syntax like for<F: Fn()> |f: F| { ... }, then perhaps we could work around this. The suggestion to make a generic function is a good one.

Why does the binary + operator not work with two &mut int?

fn increment(number: &mut int) {
// this fails with: binary operation `+` cannot be applied to type `&mut int`
//let foo = number + number;
let foo = number.add(number);
println!("{}", foo);
}
fn main() {
let mut test = 5;
increment(&mut test);
println!("{}", test);
}
Why does number + number fail but number.add(number) works?
As a bonus question: The above prints out
10
5
Am I right to assume that test is still 5 because the data is copied over to increment? The only way that the original test variable could be mutated by the increment function would be if it was send as Box<int>, right?
number + number fails because they're two references, not two ints. The compiler also tells us why: the + operator isn't implemented for the type &mut int.
You have to dereference with the dereference operator * to get at the int. This would work let sum = *number + *number;
number.add(number); works because the signature of add is fn add(&self, &int) -> int;
Am I right to assume that test is still 5 because the data is copied
over to increment? The only way that the original test variable could
be mutated by the increment function would be if it was send as
Box, right?
Test is not copied over, but is still 5 because it's never actually mutated. You could mutate it in the increment function if you wanted.
PS: to mutate it
fn increment(number: &mut int) {
*number = *number + *number;
println!("{}", number);
}

Resources