I have the following definition in module Helper.
module Helper
let (|InvariantEqualLooooongName|_|) (str : string) arg =
if String.Compare(str, arg, StringComparison.OrdinalIgnoreCase) = 0 then Some()
else None
And I want to use it in another module.
let rec MyFunc .... =
let alias = Helper.InvariantEqualLooooongName // Error: The value, constructor, namespace or type 'InvariantEqualLooooongName' is not defined
match a with
| alias "xxx" :: tail -> .....
| alias "yyyy" :: tail -> ....
| alias "zzzz" :: tail -> ...
| alias "123" :: tail -> ...
However, it got the error of
The value, constructor, namespace or type 'InvariantEqualLooooongName' is not defined
How to define the alias for active pattern?
You can create an alias for active pattern like this:
let alias = Helper.(|InvariantEqualLooooongName|_|)
But I believe you cannot use it in match expression because it will not be recognized without special symbols. To be able to use an alias you have to define it like this:
let (|Alias|_|) = Helper.(|InvariantEqualLooooongName|_|)
Related
I have a DU and I'm overriding the Equals method. Based on the current DU value, I would like to call the base equality method or my custom one. However, it's not letting me access "base". Any idea on how to work around this?
type Test =
| A of string
| B of int64
override this.Equals(other) =
let other' = other :?> Test
match other' with
| A str -> str = "a"
| B i -> base.Equals this other //how do I do this?
First, any F# discriminated union will have obj as base class, so just use obj.Equals.
Second, Equals is a .NET method, not an F# function, so its arguments must be given in a tupled form - i.e. Equals(x,y) instead of Equals x y.
Finally, if you implement a custom Equals, you also need to add [<CustomEquality; NoComparison>]
So:
[<CustomEquality; NoComparison>]
type Test =
| A of string
| B of int64
override this.Equals(other) =
let other' = other :?> Test
match other' with
| A str -> str = "a"
| B i -> obj.Equals(this, other)
I have an F# Discriminated Union, where I want to apply some "constructor logic" to any values used in constructing the union cases. Let's say the union looks like this:
type ValidValue =
| ValidInt of int
| ValidString of string
// other cases, etc.
Now, I want to apply some logic to the values that are actually passed-in to ensure that they are valid. In order to make sure I don't end up dealing with ValidValue instances that aren't really valid (haven't been constructed using the validation logic), I make the constructors private and expose a public function that enforces my logic to construct them.
type ValidValue =
private
| ValidInt of int
| ValidString of string
module ValidValue =
let createInt value =
if value > 0 // Here's some validation logic
then Ok <| ValidInt value
else Error "Integer values must be positive"
let createString value =
if value |> String.length > 0 // More validation logic
then Ok <| ValidString value
else Error "String values must not be empty"
This works, allowing me to enforce the validation logic and make sure every instance of ValidValue really is valid. However, the problem is that no one outside of this module can pattern-match on ValidValue to inspect the result, limiting the usefulness of the Discriminated Union.
I would like to allow outside users to still pattern-match and work with the ValidValue like any other DU, but that's not possible if it has a private constructor. The only solution I can think of would be to wrap each value inside the DU in a single-case union type with a private constructor, and leave the actual ValidValue constructors public. This would expose the cases to the outside, allowing them to be matched against, but still mostly-prevent the outside caller from constructing them, because the values required to instantiate each case would have private constructors:
type VInt = private VInt of int
type VString = private VString of string
type ValidValue =
| ValidInt of VInt
| ValidString of VString
module ValidValue =
let createInt value =
if value > 0 // Here's some validation logic
then Ok <| ValidInt (VInt value)
else Error "Integer values must be positive"
let createString value =
if value |> String.length > 0 // More validation logic
then Ok <| ValidString (VString value)
else Error "String values must not be empty"
Now the caller can match against the cases of ValidValue, but they can't read the actual integer and string values inside the union cases, because they're wrapped in types that have private constructors. This can be fixed with value functions for each type:
module VInt =
let value (VInt i) = i
module VString =
let value (VString s) = s
Unfortunately, now the burden on the caller is increased:
// Example Caller
let result = ValidValue.createInt 3
match result with
| Ok validValue ->
match validValue with
| ValidInt vi ->
let i = vi |> VInt.value // Caller always needs this extra line
printfn "Int: %d" i
| ValidString vs ->
let s = vs |> VString.value // Can't use the value directly
printfn "String: %s" s
| Error error ->
printfn "Invalid: %s" error
Is there a better way to enforce the execution of the constructor logic I wanted at the beginning, without increasing the burden somewhere else down the line?
You can have private case constructors but expose public active patterns with the same names. Here's how you would define and use them (creation functions omitted for brevity):
module Helpers =
type ValidValue =
private
| ValidInt of int
| ValidString of string
let (|ValidInt|ValidString|) = function
| ValidValue.ValidInt i -> ValidInt i
| ValidValue.ValidString s -> ValidString s
module Usage =
open Helpers
let validValueToString = function
| ValidInt i -> string i
| ValidString s -> s
// 😎 Easy to use ✔
// Let's try to make our own ValidInt 🤔
ValidInt -1
// error FS1093: The union cases or fields of the type
// 'ValidValue' are not accessible from this code location
// 🤬 Blocked by the compiler ✔
Unless there's a particular reason that a discriminated union is required, given the particular use case you've provided it sounds like you don't actually want a discriminated union at all since an active pattern would be more useful. For example:
let (|ValidInt|ValidString|Invalid|) (value:obj) =
match value with
| :? int as x -> if x > 0 then ValidInt x else Invalid
| :? string as x -> if x.Length > 0 then ValidString x else Invalid
| _ -> Invalid
At that point, callers can match and be assured that the logic has been applied.
match someValue with
| ValidInt x -> // ...
| _ -> // ...
I have a situation in finding a sequence of strings that have patterns like XXXX or CCCC or "IIII". I have tried the following code, but it does not work
let rec checkSequence roman=
let r=List.ofSeq roman
match r with
| [] -> true
| a::b::c::d::tail when (a="I" || a="X" || a="C") && a=b && a=c && a=d -> false
| head::tail -> checkSequence tail
checkSequence "CCC"
The error is: This expression was expected to have type string list but here has type string
1-How can I resolve this error?
2-Is there any simpler way to find this patterns?
If you need use a recursion on list you may do something like this:
let checkSequenceStr str =
let rec checkSequence roman =
match roman with
| [] -> true
| 'I'::'I'::'I'::'I'::tail -> false
| 'X'::'X'::'X'::'X'::tail -> false
| 'C'::'C'::'C'::'C'::tail -> false
| head::tail -> checkSequence tail
checkSequence (str |> List.ofSeq)
Or you could use .NET string methods to check patterns directly (which is easier):
let checkPattern (str : string) =
["IIII";"CCCC";"XXXX"] |> List.exists str.Contains |> not
You are using List.ofSeq, this will type force the roman parameter to be of an type list.
https://msdn.microsoft.com/en-us/library/ee340325.aspx
Therefor your error This expression was expected to have type string list but here has type string is due to calling the function wrongly, then an logical error. Therefor change:
checkSequence "CCC"
Into:
checkSequence ["C"; "C";"C"]
I want to use the following code to restrict there is only one argument. However, I got the following error at first :: NIL?
Error 1 This expression was expected to have type
string []
but here has type
'a list
[<EntryPoint>]
let main argv =
match argv with
| first :: NIL ->
.... do something with first
| _ -> failwith "Must have only one argument."
The command line arguments are passed as an array, not a list.
Do something like this if you expect exactly one argument:
match argv with
| [|first|] ->
// .... do something with first
| _ -> failwith "Must have only one argument."
As mentioned in the accepted answer the "args" argument to the entrypoint is an array, not a list, so you cannot use it with the syntax for list matching.
Instead of matching on the array, as suggested above, you could turn the arguments into an actual list and use that for matching. I have found that a very useful way to handlie command line arguments (though it may be overkill for your example case). As an example:
[<EntryPoint>]
let main args =
let arglist = args |> List.ofSeq
match arglist with
| first :: [] ->
// do something with 'first'
| _ -> // catches both the no-argument and multi-argument cases
printfn "Usage : "
// print usage message
Edit:
As for more complicated examples there are two ways to go from here. You can of course add more complicated cases in the match, or you could parse the list of arguments in a recursive way to build an object representing options and arguments. The latter would get a bit too complicated to fit here, but as an example of some more complex match cases, here is some code related to some recent work where the executable accepts a "command" to operate on a target file, and each command has different further arguments (each command calls a function whose implementation I left out for sake of brevity)
[<EntryPoint>]
let main args =
let arglist = args |> List.ofSeq
match arglist with
| target :: "list" :: [] ->
listContent target
| target :: "remove" :: name :: [] ->
removeContent target name
| target :: "add" :: name :: [] ->
addContent target name
| target :: "addall" :: names ->
for name in names do
addContent target name
| _ -> // catches cases not covered above
printfn "Usage : "
// print usage message
How about Active Patterns for parsing individual commands, returning an Option indicating None on failure and Some with the content of recovered parameters, possibly nestled in their own dedicated type. Converting "argv" to "string list" is merely a convenience act due to the convenience of list syntax in F#. Note: there are a lot of type annotations here that are typically unnecessary.
type Cmd1Parms = ....
type Cmd2Parms = ....
let performCmd1 cmd1Parms = ...
let performCmd2 cmd2Parms = ...
let commandNotFound argL = ...
let (|ParseForCmd1|_|) argL : Cmd1Parms option = ....
let (|ParseForCmd2|_|) argL : Cmd2Parms option = ....
[<EntryPoint>]
let main argv =
let argL = List.ofSeq<string> argv
match argL with
| ParseForCmd1 cmd1Parms -> performCmd1 cmd1Parms
| ParseForCmd2 cmd2Parms -> performCmd2 cmd2Parms
| _ -> commandNotFound argL
If there's another way to achieve what I'm trying to do below, please let me know. Suppose I have the following sample code
type FooBar =
| Foo
| Bar
let foobars = [Bar;Foo;Bar]
let isFoo item =
match item with
| Foo _ -> true
| _ -> false
foobars |> Seq.filter isFoo
I want to write a generic/higher-order version of isFoo that allows me to filter my list based on all other types of the discriminated union (Bar in this case).
Something like the following, where 'a can be either Foo or Bar
let is<'a> item =
match item with
| a _ -> true
| _ -> false
However, this attempt yields the following error:
error FS0039: The pattern discriminator 'a' is not defined
If you just want to filter a list, then the easiest option is to use function to write standard pattern matching:
[ Foo; Bar; Foo ]
|> List.filter (function Foo -> true | _ -> false)
If you wanted to write some more complicated generic function that checks for a case and then does something else, then the easiest option (that will work in general) is to take a predicate that returns true or false:
let is cond item =
if cond item then
true
else
false
// You can create a predicate using `function` syntax
is (function Foo -> true | _ -> false) <argument>
In your specific example, you have a discriminated union where none of the cases has any parameters. This is probably an unrealistic simplification, but if you only care about discriminated unions without parameters, then you can just use the cases as values and compare them:
let is case item =
if case = item then
true
else
false
// You can just pass it 'Foo' as the first parameter to
// `is` and use partial function application
[ Foo; Bar; Foo ]
|> List.filter (is Foo)
// In fact, you can use the built-in equality test operator
[ Foo; Bar; Foo ] |> List.filter ((=) Foo)
This last method will not work if you have more complicated discriminated union where some cases have parameters, so it is probably not very useful. For example, if you have a list of option values:
let opts = [ Some(42); None; Some(32) ]
opts |> List.filter (is Some) // ERROR - because here you give 'is' a constructor
// 'Some' instead of a value that can be compared.
You could do various tricks using Reflection (to check for cases with a specified name) and you could also use F# quotations to get a bit nicer and safer syntax, but I do not think that's worth it, because using pattern matching using function gives you quite clear code.
EDIT - Just out of curiosity, a solution that uses reflection (and is slow, not type safe and nobody should actually use it in practice unless you really know what you're doing) could look like this:
open Microsoft.FSharp.Reflection
open Microsoft.FSharp.Quotations
let is (q:Expr) value =
match q with
| Patterns.Lambda(_, Patterns.NewUnionCase(case, _))
| Patterns.NewUnionCase(case, _) ->
let actualCase, _ = FSharpValue.GetUnionFields(value, value.GetType())
actualCase = case
| _ -> failwith "Wrong argument"
It uses quotations to identify the union case, so you can then write something like this:
type Case = Foo of int | Bar of string | Zoo
[ Foo 42; Zoo; Bar "hi"; Foo 32; Zoo ]
|> List.filter (is <# Foo #>)
As long as union cases accept the same set of parameters, you can pass a constructor as an argument and reconstruct DUs for comparison.
It looks more appealing when Foo and Bar have parameters:
type FooBar = Foo of int | Bar of int
let is constr item =
match item with
| Foo x when item = constr x -> true
| Bar x when item = constr x -> true
| _ -> false
In your example, constructors have no argument. So you can write is in a simpler way:
type FooBar = Foo | Bar
let is constr item = item = constr
[Bar; Foo; Bar] |> Seq.filter (is Foo)