When specifying an implicit function in VDM-SL, is it possible to specify a curried function? In the following test1 and test2 are explicit uncurried and curried functions, and test3 is an implicit uncurried function. All are accepted by Overture. test4 is an attempt at an implicit curried function, but it is rejected by Overture.
Also, is there any way to specify with an implicit function definition that it should be total?
module moduleName
exports all
definitions
functions
test1 : nat * nat +> nat
test1 (arg1,arg2) == arg1+arg2;
test2 : nat -> nat +> nat
test2 (arg1) (arg2) == arg1+arg2;
test3 (arg1:nat,arg2:nat) res:nat
post res = arg1+arg2;
test4 (arg1:nat) (arg2:nat) res:nat
post res = arg1+arg2;
end moduleName
No, I'm afraid curried functions are only provided for explicit function definitions. And there is no partial/total indicator for implicit definitions.
(I just asked why we have this difference. It seems it is to do with the history of the language: the English school produced implicit functions but without currying, whereas the Danish school had explicit functions with currying. They ought really to be harmonized - and your guessed syntax would probably be the result.)
Related
Here is a function:
let newPositions : PositionData list =
positions
|> List.filter (fun x ->
let key = (x.Instrument, x.Side)
match brain.Positions.TryGetValue key with
| false, _ ->
// if we don't know the position, it's new
true
| true, p when x.UpdateTime > p.UpdateTime ->
// it's newer than the version we have, it's new
true
| _ ->
false
)
it compiles at expected.
let's focus on two lines:
let key = (x.Instrument, x.Side)
match brain.Positions.TryGetValue key with
brain.Positions is a Map<Instrument * Side, PositionData> type
if I modify the second line to:
match brain.Positions.TryGetValue (x.Instrument, x.Side) with
then the code will not compile, with error:
[FS0001] This expression was expected to have type
'Instrument * Side'
but here has type
'Instrument'
but:
match brain.Positions.TryGetValue ((x.Instrument, x.Side)) with
will compile...
why is that?
This is due to method call syntax.
TryGetValue is not a function, but a method. A very different thing, and a much worse thing in general. And subject to some special syntactic rules.
This method, you see, actually has two parameters, not one. The first parameter is a key, as you expect. And the second parameter is what's known in C# as out parameter - i.e. kind of a second return value. The way it was originally meant to be called in C# is something like this:
Dictionary<int, string> map = ...
string val;
if (map.TryGetValue(42, out val)) { ... }
The "regular" return value of TryGetValue is a boolean signifying whether the key was even found. And the "extra" return value, denoted here out val, is the value corresponding to the key.
This is, of course, extremely awkward, but it did not stop the early .NET libraries from using this pattern very widely. So F# has special syntactic sugar for this pattern: if you pass just one parameter, then the result becomes a tuple consisting of the "actual" return value and the out parameter. Which is what you're matching against in your code.
But of course, F# cannot prevent you from using the method exactly as designed, so you're free to pass two parameters as well - the first one being the key and the second one being a byref cell (which is F# equivalent of out).
And here is where this clashes with the method call syntax. You see, in .NET all methods are uncurried, meaning their arguments are all effectively tupled. So when you call a method, you're passing a tuple.
And this is what happens in this case: as soon as you add parentheses, the compiler interprets that as an attempt to call a .NET method with tupled arguments:
brain.Positions.TryGetValue (x.Instrument, x.Side)
^ ^
first arg |
second arg
And in this case it expects the first argument to be of type Instrument * Side, but you're clearly passing just an Instrument. Which is exactly what the error message tells you: "expected to have type 'Instrument * Side'
but here has type 'Instrument'".
But when you add a second pair of parens, the meaning changes: now the outer parens are interpreted as "method call syntax", and the inner parens are interpreted as "denoting a tuple". So now the compiler interprets the whole thing as just a single argument, and all works as before.
Incidentally, the following will also work:
brain.Positions.TryGetValue <| (x.Instrument, x.Side)
This works because now it's no longer a "method call" syntax, because the parens do not immediately follow the method name.
But a much better solution is, as always, do not use methods, use functions instead!
In this particular example, instead of .TryGetValue, use Map.tryFind. It's the same thing, but in proper function form. Not a method. A function.
brain.Positions |> Map.tryFind (x.Instrument, x.Side)
Q: But why does this confusing method even exist?
Compatibility. As always with awkward and nonsensical things, the answer is: compatibility.
The standard .NET library has this interface System.Collections.Generic.IDictionary, and it's on that interface that the TryGetValue method is defined. And every dictionary-like type, including Map, is generally expected to implement that interface. So here you go.
In future, please consider the Stack Overflow guidelines provided under How to create a Minimal, Reproducible Example. Well, minimal and reproducible the code in your question is, but it shall also be complete...
…Complete – Provide all parts someone else needs to reproduce your
problem in the question itself
That being said, when given the following definitions, your code will compile:
type Instrument() = class end
type Side() = class end
type PositionData = { Instrument : Instrument; Side : Side; }
with member __.UpdateTime = 0
module brain =
let Positions = dict[(Instrument(), Side()), {Instrument = Instrument(); Side = Side()}]
let positions = []
Now, why is that? Technically, it is because of the mechanism described in the F# 4.1 Language Specification under §14.4 Method Application Resolution, 4. c., 2nd bullet point:
If all formal parameters in the suffix are “out” arguments with byref
type, remove the suffix from UnnamedFormalArgs and call it
ImplicitlyReturnedFormalArgs.
This is supported by the signature of the method call in question:
System.Collections.Generic.IDictionary.TryGetValue(key: Instrument * Side, value: byref<PositionData>)
Here, if the second argument is not provided, the compiler does the implicit conversion to a tuple return type as described in §14.4 5. g.
You are obviously familiar with this behaviour, but maybe not with the fact that if you specify two arguments, the compiler will see the second of them as the explicit byref "out" argument, and complains accordingly with its next error message:
Error 2 This expression was expected to have type
PositionData ref
but here has type
Side
This misunderstanding changes the return type of the method call from bool * PositionData to bool, which consequently elicits a third error:
Error 3 This expression was expected to have type
bool
but here has type
'a * 'b
In short, your self-discovered workaround with double parentheses is indeed the way to tell the compiler: No, I am giving you only one argument (a tuple), so that you can implicitly convert the byref "out" argument to a tuple return type.
Is it possible to store a procedure as a property of a derived type? I was thinking of something along the lines of:
module funcs_mod
public :: add
contains
function add(y,z) result (x)
integer,intent(in) :: y,z
integer :: x
x = y + z
end function
end module
module type_A_mod
use funcs_mod
public :: type_A,set_operator
type type_A
procedure(),pointer,nopass :: operator
end type
contains
subroutine set_operator(A,operator)
external :: operator
type(type_A),intent(inout) :: A
A%operator => operator
end subroutine
function operate(A,y,z) result(x)
type(type_A),intent(in) :: A
integer,intent(in) :: y,z
integer :: x
x = A%operator(y,z)
end function
end module
program test
use type_A_mod
use funcs_mod
type(type_A) :: A
call set_operator(A,add)
write(*,*) operate(A,1,2)
end program
But this doesn't successfully compile. Several errors are displayed including:
1) Syntax error in procedure pointer component
and
2) 'operator' at (1) is not a member of the 'type_a' structure
As well as some unsuccessful use statements. Is there a way to do this correctly? Any help is greatly appreciated.
UPDATE:
I've modified procedure,pointer to procedure(),pointer and now the errors are
1) FUNCTION attribute conflicts with SUBROUTINE attribute in 'operator'
and
2) Can't convert UNKNOWN to INTEGER(4)
Both refer to the line x = A%operator(y,z)
As you have discovered, the syntax for declaring a procedure pointer declaration requires procedure([interface]), pointer [, ...] :: .... You chose procedure(), pointer, nopass :: operator.
The consequence of procedure() is that you are not declaring whether operator is a function or a subroutine. There is nothing untoward in this, but more work then remains in convincing the compiler that you are using the references consistently. Your compiler appears to not believe you.
Rather than go into detail of what the compiler thinks you mean, I'll take a different approach.
You reference A%operator for a structure A of type with that component as the result of the function operate. You say clearly in declaring this latter function that its result is an integer.
Now, assuming that you don't want to do exciting things with type/kind conversion to get to that integer result, we'll take that you always intend for A%operator to be a function with integer result. That means you can declare that procedure pointer component to be a function with integer result.
This still leaves you with choices:
type type_A
procedure(integer),pointer,nopass :: operator
end type
being a function with integer result and implicit interface, and
type type_A
procedure(add),pointer,nopass :: operator
end type
being a function with explicit interface matching the function add.
Your ongoing design choices inform your final decision.
As a final note, you aren't using implicit none. This is important when we consider your line
external :: operator
If operator is a function then (by implicit typing rules) it has a (default) real result. So, you want to change to one of the following
integer, external :: operator
or
procedure(integer) :: operator
or
procedure(add) :: operator
To conclude, and echo the comment by Vladimir F, think very carefully about your design. You currently have constraints from the reference of operate (in the function result and its arguments) that look like you really do know that the component will have a specific interface. If you are sure of that, then please do use procedure(add) as the declaration/
Have this function defined in your module:
module Data
int inc(x) = x + 1;
Type this in the console:
rascal> import Data;
rascal> import List;
This works:
rascal> inc(1);
int: 2
But this does not:
rascal> list[int] y = [1,2,3];
rascal> mapper(y, inc);
|rascal://<path>|: insert into collection not supported on value and int
☞ Advice
But it works if inc(...)'s parameter type is declared:
int inc(int x) = x + 1;
So why does not having this type declaration work for using the inc(...) function directly, but not for passing that function to mapper(...)?
Because Rascal's type checker is still under development, you are not warned if you make a small mistake like forgetting to provide a type for a function parameter. It may still work, accidentally, in some circumstances but you are guaranteed to run into trouble somewhere as you've observed. The reason is that type inference for function parameters is simply not implemented as a feature. This is a language design decision with the intent of keeping error messages understandable.
So, this is not allowed:
int f(a) = a + 1;
And, it should be written like this:
int f(int a) = a + 1;
I consider it a bug that the interpreter doesn't complain about an untyped parameter. It is caused by the fact that we reuse the pattern matching code for both function parameters and inline patterns. [edit: issue has been registered at https://github.com/cwi-swat/rascal/issues/763]
In your case the example works because dynamically the type of the value is int and addition does not check the parameter types. The broken example breaks because the interpreter does checks the type of the function parameter at the call-site (which defaulted to value for the untyped parameter).
C# and F# has different implementation of the default (or optional) parameters.
In C# language when you add default value to the argument you'll not change its underlying type (I mean type of the parameter). Actually optional arguments in C# is a lightweight syntactic sugar:
class CSharpOptionalArgs
{
public static void Foo(int n = 0) {}
}
// Somewhere in the call site
CSharpOptionalArgs.Foo();
// Call to Foo() will be transformed by C# compiler
// *at compile time* to something like:
const int nArg = GetFoosDefaultArgFromTheMetadata();
CSharpOptionalArgs.Foo(nArg);
But F# implements this feature in a different way. Unlike C#, F# optional arguments resolves at callee site but not at caller site:
type FSharpOptionalArgs() =
static let defaultValue() = 42
static member public Foo(?xArg) =
// Callee site decides what value to use if caller does not specifies it
let x = defaultArg xArg (defaultValue())
printfn "x is %d" x
This implementation is absolutely reasonable and much more powerful. C# optional arguments restricted only to compile-time constants (because optional arguments stored in assemblies metadata). In F# default value could be less obvious but we can use arbitrary expression as a default value. So far so good.
F# optional arguments transformed by F# compiler to Microsoft.FSharp.Core.FSharpOption<'a> which is a reference type. This means that every call to the method with optional argument in F# will lead to additional allocation at the managed head and will lead to pressure to garbage collection.
**EDITED**
// This call will NOT lead to additional heap allocation!
FSharpOptionalArgs.Foo()
// But this one will do!
FSharpOptionalArgs.Foo(12)
I don't worry about application code, but this behavior could dramatically degrade performance for libraries. What if some library method with an optional argument will be called thousands times per second?
This implementation seems really odd to me. But maybe there is some rules that library developer should avoid using of this feature or F# team is going to change this behavior in the future version of F#?
Following unit test profs that optional arguments are reference type:
[<TestFixture>]
type FSharpOptionalArgumentTests() =
static member public Foo(?xArg) =
// Callee site decides what value to use if caller does not specifies it
let x = defaultArg xArg 42
()
[<Test>]
member public this.``Optional argument is a reference type``() =
let pi = this.GetType().GetMethod("Foo").GetParameters() |> Seq.last
// Actually every optional parameter in F# is a reference type!!
pi.ParameterType |> should not' (equal typeof<int>)
pi.ParameterType.IsValueType |> should be False
()
Because nobody in F# team is not interesting yet in compiling "simple", Option-like discriminated unions as value types, supporting pattern-matching over such unions and so on :)
Remember, tuples types are heavly used in functional languages like F# (much more than default arguments), but still implemented in CLR as refererence types - nobody cares about memory allocation and functional_languages-specific GC tweaks.
F# 4.1 has C# optional attribute compatibility. However if you are developing function that will be consumed also by F# then you should use regular syntax:
member this.M (?i : int) =
let iv = defaultArg i 12
iv + 1
F# 4.1 optional arguments documentation:
https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/members/methods
In F#, I'd like to have what I see as a fairly standard Abstract Datatype:
// in ADT.fsi
module ADT
type my_Type
// in ADT.fs
module ADT
type my_Type = int
In other words, code inside the module knows that my_Type is an int, but code outside does not. However, F# seems to have a restriction where type abbreviations specifically cannot be hidden by a signature. This code gives a compiler error, and the restriction is described here.
If my_Type were instead a discriminated union, then there is no compiler error. My question is, why the restriction? I seem to remember being able to do this in SML and Ocaml, and furthermore, isn't this a pretty standard thing to do when creating an abstract datatype?
Thanks
As Ganesh points out, this is a technical limitation of the F# compiler (and .NET runtime), because the type abbreviation is simply replaced by the actual type during the compilation. As a result, if you write a function:
let foo (a:MyType) : MyType = a + 1
The compiler will compile it as a .NET method with the following signature:
int foo(int a);
If the actual type of the abbreviation was hidden from the users of the library, then they wouldn't be able to recognize that the foo function is actually working with MyType (this information is probably stored in some F#-specific meta-data, but that is not accessible to other .NET languages...).
Perhaps the best workaround for this limiation is to define the type as a single-case discriminated union:
type MyType = MT of int
let foo (MT a) = MT(a + 1)
Working with this kind of type is quite convenient. It adds some overhead (there are new objects created when constructing a value of the type), but that shouldn't be a big issue in most of the situations.
Type abbreviations in F# are compiled away (i.e. the compiled code will use int, not MyType), so you can't make them properly abstract. In theory the compiler could enforce the abstraction within the F# world, but this wouldn't be very helpful as it would still leak in other languages.
Note that you can define a type abbreviation as private within a module:
// File1.fs
module File1
type private MyType = int
let e : MyType = 42
let f (x:MyType) = x+1
// Program.fs
module Program
do printfn "%A" (File1.f File1.e)
I am unclear why you can't hide it with a signature; I logged a bug to consider it.
From what I understand F# does not allow an abbreviation to be hidden by a signature.
I found this link where the blogger commented on this but I am not sure on the specifics of why this is the case.
My assumption is that this is a restraint set to allow more effective interop with other languages on the CLR.