The namespace or module is not defined - f#

I am trying to work through the getting started docs for F#
Visual Studio Code shows an error
If I hover my mouse over the red squiggle I see the error message
The Namespace or module ClassLibraryDemo is not defined"
Here is the code for ClassLibaryDemo.fs
namespace ClassLibraryDemo
module PigLatin =
let toPigLatin (word: string) =
let isVowel (c: char) =
match c with
| 'a' | 'e' | 'i' |'o' |'u'
| 'A' | 'E' | 'I' | 'O' | 'U' -> true
|_ -> false
if isVowel word.[0] then
word + "yay"
else
word.[1..] + string(word.[0]) + "ay"

Please check the feedback in FSI when you execute #load ClassLibraryDemo.fs. You should see something like this:
FSI: [Loading c:\Users\*****\Documents\Source\SO2017\SO180207\TestModule.fs] namespace FSI_0002.TestModule val testFunc : unit -> unit
Most probably FSI can't find your file, either because the file name is misspelt or the file is in another directory. There could be other possible causes of not being able to see a namespace, for example not restoring a project, or corrupted cache (this I haven't seen in a while).

Related

Matching a character to a discriminated union

I created a discriminated union which has three possible options:
type tool =
| Hammer
| Screwdriver
| Nail
I would like to match a single character to one tool option. I wrote this function:
let getTool (letter: char) =
match letter with
| H -> Tool.Hammer
| S -> Tool.Screwdriver
| N -> Tool.Nail
Visual Studio Code throws me now the warning that only the first character will be matched and that the other rules never will be.
Can somebody please explain this behaviour and maybe provide an alternative?
That's not how characters are denoted in F#. What you wrote are variable names, not characters.
To denote a character, use single quotes:
let getTool (letter: char) =
match letter with
| 'H' -> Tool.Hammer
| 'S' -> Tool.Screwdriver
| 'N' -> Tool.Nail
Apart from the character syntax (inside single quotes - see Fyodor's response), you should handle the case when the letter is not H, S or N, either using the option type or throwing an exception (less functional but enough for an exercise):
type Tool =
| Hammer
| Screwdriver
| Nail
module Tool =
let ofLetter (letter: char) =
match letter with
| 'H' -> Hammer
| 'S' -> Screwdriver
| 'N' -> Nail
| _ -> invalidArg (nameof letter) $"Unsupported letter '{letter}'"
Usage:
> Tool.ofLetter 'S';;
val it : Tool = Screwdriver
> Tool.ofLetter 'C';;
System.ArgumentException: Unsupported letter 'C' (Parameter 'letter')

F# pattern matching: how "as" is interpreted when used incorrectly with constructor?

I have a discriminated union with a choice that has another du as its type as follows:
type DunionSubset =
| X
| Y
type Dunion =
| A
| B
| C of DunionSubset
I want to produce a mapping to a list of strings for Dunion type, which naturally extends to C and therefore DunionSubset
When I incorrectly use as to assign an alias to constructor as follows:
let MappingsOfC = function
| X -> ["x"]
| Y -> ["y"]
let StringMappings = function
| A -> ["a";"A"]
| B -> []
| C as c -> (MappingsOfC c)
the compiler gives me:
[FS0019] This constructor is applied to 0 argument(s) but expects 1
How exactly is my incorrect use of as above leading to this compiler error? Interestingly, the location of the compiler error is that of C, not my use of c in MappingsOfC c though Rider ide underlines c and provides a different error.
C as c matches the function argument against the pattern C and also binds it to c. So it's the same as:
let StringMappings c = match c with
| A -> ["a";"A"]
| B -> []
| C -> (MappingsOfC c)
except that this will make c visible in all branches whereas the version with as only makes c visible in the branch that has the as pattern (naturally).
You get an error because C takes an argument, but you're trying to use it without one. If you wrote | A as a ->, | B as b -> and/or | C _ as c, that would work fine.
Actually the left part of -> (before the as and when keywords, if provided) in a matching branch is a pattern. And pattern must be valid - depending on the type of the value provided right after the match keyword.
Here compiler will understand that you are wanting to match a Dunion value because it sees the patterns A and B (which are all valid) first.
Now you can see that C is an invalid pattern for Dunion. The valid pattern here must be: C something
If you don’t care about something (don’t need to use it), still, you must provide a wildcard _ to make the pattern valid: C _
But in your example, I’m pretty sure that you do care, so the code should be like this:
| C c -> MappingsOfC c

Does F# naming conventions forbids having the same name inside different disc. union types?

I have a common type in one module and that type is used inside two other discriminated union types.
I named them with the same name because of convenience. Other names are different. Next thing, I am trying to make a helper that prints types in console.
The first line fails to compile because of the type mismatch inside the match-case. I've tried a few things and it still fails with or without opening modules, forcing type and so on.
The other thing is, if I change the manes to Common1 and Common2 it works without any problems.
I remember reading that types with the same signatures are stored inside the same internal type, but my real-life example has different signatures and still fails.
Am I missing a point somewhere?
Example:
Example fails to compile with error:
Error This expression was expected to have type OneA but here has type OneB
module commonThings =
type CommonThing =
| Comm1 of int
| Comm2 of int
module thingA =
open commonThings
type OneA =
| A1 of string
| Common of CommonThing
| A2 of string
module thingB =
open commonThings
type OneB =
| B1 of string
| Common of CommonThing
| B2 of string
module printAB =
open commonThings
open thingA
open thingB
let printA (msg:OneA) =
match msg with
| A1 v -> printfn "A1"
| Common v -> printfn "Common"
| A2 v -> printfn "A2"
module main =
[<EntryPoint>]
let main argv =
printfn "%A" argv
0 // return an integer exit code
When you open thingB module, type OneB comes into scope and the Common case label from type OneA gets shadowed with the one from type OneB.
When name clashes between types or union/active pattern cases occur, the most recent one wins. Reordering the opens would make it work by chance:
open thingB
open thingA
The right solution is to prefix the case name. There's also RequireQualifiedAccess attribute you can use to force a type (or module) to always require prefixes for its internals.
You can disambiguate by prefixing the type name:
let printA (msg:OneA) =
match msg with
| A1 v -> printfn "A1"
| OneA.Common v -> printfn "Common"
| A2 v -> printfn "A2"

Location in syntax trees

When writing a parser, I want to remember the location of lexemes found, so that I can report useful error messages to the programmer, as in “if-less else on line 23” or ”unexpected character on line 45, character 6” or “variable not defined” or something similar. But once I have built the syntax tree, I will transform it in several ways, optimizing or expanding some kind of macros. The transformations produce or rearrange lexemes which do not have a meaningful location.
Therefore it seems that the type representing the syntax tree should come in two flavor, a flavor with locations decorating lexemes and a flavor without lexemes. Ideally we would like to work with a purely abstract syntax tree, as defined in the OCaml book:
# type unr_op = UMINUS | NOT ;;
# type bin_op = PLUS | MINUS | MULT | DIV | MOD
| EQUAL | LESS | LESSEQ | GREAT | GREATEQ | DIFF
| AND | OR ;;
# type expression =
ExpInt of int
| ExpVar of string
| ExpStr of string
| ExpUnr of unr_op * expression
| ExpBin of expression * bin_op * expression ;;
# type command =
Rem of string
| Goto of int
| Print of expression
| Input of string
| If of expression * int
| Let of string * expression ;;
# type line = { num : int ; cmd : command } ;;
# type program = line list ;;
We should be allowed to totally forget about locations when working on that tree and have special functions to map an expression back to its location (for instance), that we could use in case of emergency.
What is the best way to define such a type in OCaml or to handle lexeme positions?
The best way is to work always with AST nodes fully annotated with the locations. For example:
type expression = {
expr_desc : expr_desc;
expr_loc : Lexing.position * Lexing.position; (* start and end *)
}
and expr_desc =
ExpInt of int
| ExpVar of string
| ExpStr of string
| ExpUnr of unr_op * expression
| ExpBin of expression * bin_op * expression
Your idea, keeping the AST free of locations and writing a function to retrieve the missing locations is not a good idea, I believe. Such a function should require searching by pointer equivalence of AST nodes or something similar, which does not really scale.
I strongly recommend to look though OCaml compiler's parser.mly which is a full scale example of AST with locations.

FSLex Unknown Error

I got some problem with my FSLex which I can't solve... All I know is that fslex.exe exited with code 1...
The F# code at the top was tested in F# Interactive, so the problem isn't there (I can't see how).
Lexer:
http://pastebin.com/qnDnUh59
And Parser.fsi:
http://pastebin.com/sGyLqZbN
Thanks,
Ramon.
Non-zero error means the lexer failed, usually it'll describe the failure too. When I compile, I get exited with code 1 along with this:
Unexpected character '\'
let id = [\w'.']+
----------^
Lexer doesn't like char literals outside of quotes, and it doesn't understand the meaning of \w either. According to FsLex source code, FsLex only understands the following escape sequences:
let escape c =
match c with
| '\\' -> '\\'
| '\'' -> '\''
| 'n' -> '\n'
| 't' -> '\t'
| 'b' -> '\b'
| 'r' -> '\r'
| c -> c
This fixed version of your lexer compiles fine for me: http://pastebin.com/QGNk3VKD

Resources