Unexpected keyword 'member' in definition, in a F# module - f#

Trying to get optional parameters working in a module I tried changing the let to member and static member but that yields errors.
Error FS0010 Unexpected keyword 'member' in definition. Expected incomplete structured construct at or before this point or other token.
OK syntax:
module Kingdom =
let Rule years = ()
Bad syntax
module Kingdom =
member this.Rule years = ()
Can you not define a member in a module?

As documentation states
Members are features that are part of a type definition [...] F# object types such as records, classes, discriminated unions, interfaces, and structures support members.
That's why you cannot define member in module directly.

Related

How to define optional parameters in F# modules?

I'm trying to re-write a tiny C# lib in F# and I've encountered an error. I'm trying to define optional parameters for a method in a module but the compiler says "Optional arguments are only permitted on type members".
I've checked why you can't use them in loose functions but when typing static member or member I get another error instead.
module Kingdom =
let Rule (?years : int) =
()
I thought this was going to wor kas it's how I understood you type it, after reading the Microsoft Docs article about it.
By using another way to define the "static class" you can add member to it. And then you can use optional parameters. The class will show up as a normal static class in C#.
[<AbstractClass; Sealed>]
type Kingdom private () =
static member Rule (?years : int) = ()

Get type of a module at compile time in F#

We know that in C# we can get type of a type at compile time using typeof(OutType) this lets us pass this to attributes later as it is constant expression.
I saw this question, but it doesn't really address the compile time usage.
So my question is: Is there a way to get System.Type of a given module at compile type within F# standard library?
F# disallows obtaining a module's type using its typeof operator by design, as they're not first-class concepts in the language.
From the spec, section 13.2:
F# modules are compiled to provide a corresponding compiled CLI type declaration and
System.Type object, although the System.Type object is not accessible by using the typeof
operator.
Modules compile to static classes however, so it is possible to obtain the type at runtime using reflection (and that's what happens in typeof<MyModule.Dummy>.DeclaringType example), and it's possible to obtain the type of a module defined in a referenced F# assembly using typeofoperator in C#.
For what you're trying to do, you'd best use a class instead of a module, because then you can get hold of the type without hassle:
type MyFactoryClass =
static member TestCases = [ 1; 2; 3 ]
...
[<Test; TestCaseSource(typeof<MyFactoryClass>, "TestCases">]
let test (arg: int) = ...
If you are OK to refer to a type inside that module (or create a dummy one if there are no types), you could do this:
module MyModule =
type Dummy = Dummy
let myModule = typeof<MyModule.Dummy>.DeclaringType

Getting FS0035 => Construct is deprecated

In a fsyacc based project, I have this line:
type 'a cucomment = string
This is the full error description I'm getting:
CALast.fs(117,9): error FS0035: This construct is deprecated: This
type abbreviation has one or more declared type parameters that do not
appear in the type being abbreviated. Type abbreviations must use all
declared type parameters in the type being abbreviated. Consider
removing one or more type parameters, or use a concrete type
definition that wraps an underlying type, such as 'type C<'a> = C of
...'.
Any idea how to solve this?
F# no longer allows type aliases that add generic type parameters to a type without declaring a new type. If you want to define a generic type that wraps some other type, you have to use some constructor. For example, you can use single-case discriminated union:
type 'a Cucomment = CC of string
Unfortunately, this means that you'd have to change all code that uses the type to unwrap the value using pattern matching or by adding Value member to the type.
The only case where generic type aliases are allowed is when you declare a version of type with units of measure, which requires a special attribute. However, this is probably not going to work for you (because units behave quite differently):
[<MeasureAnnotatedAbbreviation>]
type 'a Cucomment = string
If this is in some code generated by fsyacc, then that's a bug in fsyacc that should be fixed (I think this was quite recent change). In that case, report it to fsbugs at microsoft dot com.

Is it possible to declare a type at function scope in F#?

Let's say I have a function which does something pretty complicated and it is implemented with the help of subfunctions. To make things easier, instead of tuples I would like to use some intermediate structures which are private to the implementation of this function.
I don't want the declaration of these structures to leak outside. So I want something like this:
let someComplexFun p =
type SomeRecord = {i:int; x:int; y:int;}
type SomeOtherRecord = {...}
let innerFunctionA (x:SomeRecord) = ...
let innerFunctionB (x:SomeOtherRecord) = ...
...
I tried it but of course the compiler doesn't let me do this. I looked at the documentation and I can't see anywhere quickly that the types must be declared at the module level.
In LISP for example, it seems that it's all entirely legal, e.g.:
(defun foo (when)
(declare (type (member :now :later) when)) ; Type declaration is illustrative and in this case optional.
(ecase when
(:now (something))
(:later (something-else))))
So, am I missing something? Is this possible if F# at all?
To verify that this is not allowed according to the specification, take a look at the grammar of F# expressions in the specification: Section 6: Expressions. It lists various constructs that can be used in place of expr and none of them is a type declaration type-defn (described in Section 8: Type Declarations).
The (simplified) syntax for function declarations is let ident args = expr, so the body has to be an expression (and you cannot declare types inside expressions).
Types can only be declared at module or namespace scope in F#.
(You can use access modifiers like internal or signature files to hide types from other components.)
What Brian said.
heres a link to some more information http://www.ctocorner.com/fsharp/book/ch17.aspx

Unknown need for type annotation or cast

I know I must be missing something really obvious here. B.GetInstance().Call() generates the error: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved.
I'm using v1.9.9.9.
type A() =
member x.Call() = B.GetInstance().Call()
and B() =
static member GetInstance() = new B()
member x.Call() = ()
I just discovered that this works: (B.GetInstance() :> B).Call()
Any idea why the cast is necessary?
Frequently when you've got a recursive set of methods whose types to infer, F# needs help. A more pleasant alternative would be to annotate the definition of B.GetInstance:
type A() =
member x.Call() = B.GetInstance().Call()
and B() =
static member GetInstance() : B = new B()
member x.Call() = ()
I believe that the reason you run into this problem is that F# tries to solve all inferred types on all methods in A and B simultaneously (because they are defined as mutually recursive types), and this leads to problems, but perhaps someone from the F# team will weigh in.
The quick summary is that in a recursive group (e.g. members in one type, or members of recursive types like we have here) F# reads the declarations in left-to-right top-to-bottom order, followed by the definitions in left-to-right top-to-bottom order. So in this instance when it reaches the definition of A.Call, it has not yet read the definition of B.GetInstance and therefore does not (yet!) know that the return type of GetInstance will be B.
Keith's answer nails it for this situation, you can provide a type annotation to specify the return type of GetInstance in its declaration.
See
Forcing F# type inference on generics and interfaces to stay loose
for a deep discussion of what's going on here.
Note also that in your original attempt, you don't need to "cast" (the potentially dynamic operation, using :>), instead you can just "annotate" (statically declare a type, using :) to get it to compile. But makes more sense to put the type annotation in the method declaration for GetInstance (generally, prefer addition annotations to method signatures instead of arbitrary places inside bodies).

Resources