I am struggling to decipher what this error means:
A unique overload for method 'Stack`1' could not be determined based
on type information prior to this program point. A type annotation may
be needed. Candidates: System.Collections.Generic.Stack(capacity: int)
: unit, System.Collections.Generic.Stack(collection:
System.Collections.Generic.IEnumerable) : unit
This error occurs when attempting to write this code:
let prepareDeck deck: Card list =
let stack = System.Collections.Generic.Stack<Card>(deck)
stack
I thought a list was of type IEnumerable.
Thus, I thought I could just drop the list inside of a Stack constructor.
What am I missing?
Here's the rest of the code:
type Suit = | Spades
| Clubs
| Diamonds
| Hearts
type Face = | Two | Three | Four | Five
| Six | Seven | Eight | Nine | Ten
| Jack | Queen | King | Ace
type Card = {Face:Face; Suit:Suit}
let private suits = [Spades; Clubs; Diamonds ; Hearts]
let private faces = [Two; Three; Four; Five; Six; Seven; Eight; Nine; Ten;
Jack; Queen; King; Ace]
let deck = [for suit in suits do
for face in faces do
yield {Face=face; Suit=suit}]
let prepareDeck deck: Card list =
let stack = System.Collections.Generic.Stack<Card>(deck)
stack
The way your code looks now, Card list is the result of the function rather than type annotation on an argument. That's why it probably looks for a stack constructor that returns a Card list rather than a Stack.
Try this:
let prepareDeck (deck: Card list) =
let stack = System.Collections.Generic.Stack<Card>(deck)
stack
Related
type GenericResult =
| Ok
| Error of string
type LoginResult =
| Ok
| UserNotFound
| WrongPassword
let check something:GenericResult =
match something with
//| true -> Ok // error:This expression was expected to be of type "GenericREsult" but here has type "LoginResult"
| true -> GenericResult.Ok // I'm forced to specify GenericResult.Ok
| false -> Error "aargg!"
let checkLogin something:LoginResult =
match something with
| true -> Ok // here I don't need to specify the DU because this is defined after
| _ -> WrongPassword
I'd like to use just "Ok" in both the methods, without the need to specify the DU.
I see that in case of clashing of the value the last one is the "predefined".
Ideally I'd like to have a sort of inheritance
to reuse part of a DU in another DU.
For example:
type GenericResult =
| Ok
| Error of string
type LoginResult =
//| GenericResult.Ok
| UserNotFound
| WrongPassword
type SaveResult =
| Created
| Updated
//| GenericResult.Error
let checkLogin something: LoginResult | GenericResult.Ok =
match something with
| true -> Ok
| _ -> WrongPassword
[EDIT]
The real scenario where I feel the need for this feature is this with 3 different results from 3 different logic classes.
There will be in the future more cases so the multiplication of duplicated DU values will increase.
// DUs ordered from the most specific to the most generic
type BalanceUpdateResult =
| Created
| Updated
| InvalidRequest of string
type DeleteResult =
| Ok
| InvalidRequest of string
type Result<'T> =
| Ok of 'T
| NotValid of string
| Error of string
The goal is to have a clean match syntax in the consumer, where the value of the DU will evenctually be used to raise an exception or to return the created value, for example.
// balance update function (result is BalanceUpdateResult):
match result with
| Created -> this.createOkWithStatus 201
| Updated -> this.createOkWithStatus 200
| InvalidRequest error -> this.createErrorForConflict error
// company creation function (result is Result<Company>):
match result with
| Result.Ok newItem ->
context.Logger.Log $"Company created. New Id:{newItem.Id}, Name:{newItem.Name}."
this.createCreated newItem
| NotValid error -> base.createErrorForConflict error
| Error error -> base.createError error
Here, for example, InvalidRequest is not accepted in the second case because it belongs to the wrong DU.
Having to specify the DU everywhere results in a mess like the following example (see the many Result<_>.):
interface ICompanyLogic with
member this.Create(company:Company):Result<Company> =
match normalize company |> validate with
| NotValid msg -> Result<_>.NotValid msg
| Valid validCompany ->
match companyRepository.Exists(validCompany.Name) with
| true -> Result<_>.NotValid($"A company with name \"{validCompany.Name}\" already exists.")
| _ ->
let newCompany = assignNewId validCompany
companyRepository.Create(newCompany)
Result<_>.Ok(newCompany)
member this.Update (company:Company):Result<Company> =
let checkNameExists company =
match companyRepository.GetByName company.Name with
| Some c when c.Id <> company.Id -> NotValid $"A company with name \"{company.Name}\" already exists."
| _ -> Valid company
match normalize company |> validate with
| NotValid msg -> Result<_>.NotValid msg
| Valid c -> match checkNameExists c with
| Valid c -> companyRepository.Update c; Result<_>.Ok c
| NotValid msg -> Result<_>.NotValid msg
I think the best way to achieve what you are trying to do would be to start with a generic Result type that has a type parameter representing the error type:
type Result<'TError> =
| Ok
| Error of 'TError
This allows you to use different types for representing errors, including string, but also another DU to capture more specific error types. You can then define GenericResult and LoginResult as two type aliases:
type LoginError =
| UserNotFound
| WrongPassword
type GenericResult = Result<string>
type LoginResult = Result<LoginError>
To report a login error, you would now use Error WrongPassword to wrap the specific error in the generic Error constructor. The implementation of your two functions looks as follows:
let check something:GenericResult =
match something with
| true -> Ok
| false -> Error "aargg!"
let checkLogin something:LoginResult =
match something with
| true -> Ok
| _ -> Error WrongPassword
Unlike TypeScript union type, F# DU are meant to be composed and not extensible - see Thomas answer for a solution using this approach.
Since F# does not offer a direct solution, you may consider renaming cases like InvalidRequest in order to be more specific and to help differentiate them when reading the code. With these specific names, you can also merge all result types into a big Event DU like what's usually done in an event sourced system:
type Event =
// BalanceUpdateResult
| BalanceCreated
| BalanceUpdated
| BalanceUpdateError of string
// DeleteResult
| DeleteOk
| DeleteError of string
// ...
Ok, as explained by Romain multiple DUs cannot solve my problem.
I decided to use the built-in type Result<'T,'TError>.
It allows me to avoid create many DUs that inevitably will have clash of names, forcing the use the full DU prefix in the code.
I solved the problem that drove me to create custom DUs with the inspiring example from Thomas reply.
(with Result<,>) I have the possibility to have dinstinct Errors or Oks.
(note the Result<unit,_> and the Result<BalanceUpdateRequest,_>)
type ICompanyLogic =
abstract member Create:Company -> Result<Company, string> // CreateResult
abstract member Update:Company -> Result<Company, string> // UpdateResult
abstract member Delete:string -> Result<unit,string> // DeleteResult
type BalanceUpdateResult =
| Created
| Updated
type IBalanceLogic =
abstract member CreateOrUpdate: request:BalanceUpdateRequest -> Result<BalanceUpdateResult, string>
Apart BalanceUpdateResult all the other DUs where replaced buy the Result<'T,'TError>.
I just maintained a couple one for specific tasks:
type CompanyValidation = Valid of Company | NotValid of string
type ValidateResult = Valid | NotValid of string
In the end with this solution:
I don't need to define many DUs
I can customize the Result... within as many values I want (storing a sub-DU in the Ok or Error union case)
I don't need to use prefix or use synonims to avoid clash (code result much cleaner)
Given the follwing code:
type Creature =
{ Strength: int
Toughness: int }
type CardType =
| Creature of Creature
| Land
| Instant
type Card =
{ Types: CardType list }
module Card =
let isType t card = List.contains t card.Types
I am able to write
Card.isType Land
When trying to check if card is a creature, i get the following error:
This expression was expected to have type
'CardType'
but here has type
'Creature -> CardType'
Is it even possible to have a "isType" function like this or am I stuck with pattern matching on a separate "isCreature" function instead?
Unless you want to resort to various reflection-based hacks, you are stuck with pattern matching. I would probably define a bit more general function using List.exist rather than List.contains (taking a predicate). Then you can easily define three functions for your specific card types:
module Card =
let isType t card =
List.exists t card.Types
let isCreature =
isType (function Creature _ -> true | _ -> false)
let isLand = isType ((=) Land)
let isInstant = isType ((=) Instant)
For Land and Instant, you can just check if the value equals the specific one you're looking for. For Creature, this requires pattern matching - but can be done quite nicely using function.
Suppose I have a DU like this:
type Fruit =
| Apple of int
| Banana of string
| Cherry of int * string
Now, I want to talk about the cases of the DU (not concrete items in the DU):
[<RequireQualifiedAccess>]
type FruitType =
| Apple
| Banana
| Cherry
module FruitType =
let ofFruit =
function
| Apple _ -> FruitType.Apple
| Banana _ -> FruitType.Banana
| Cherry _ -> FruitType.Cherry
type FruitSaladRecipe =
{
FruitsRequired : Set<FruitType>
}
As you can see, there is some code duplication here: every case of Fruit has an equivalent case in FruitType, and vice-versa.
Is there a more elegant way to write this?
Bonus points for not using reflection, this should be possible at compile-time.
This problem has come up a few times for me, but I will try to give a more concrete example.
Let's say you were building a form designer where the user can add custom elements like:
Drop downs
Text inputs
Sliders
In the menu for creating a new element, the first stage might be to pick a FormElementType:
[<RequireQualifiedAccess>]
type FormElementType =
| DropDown
| TextInput
| Slider
let! chooseFormElementType : UserInteraction<FormElementType> = ...
After choosing a FormElementType, the user will design an actual FormElement:
type FormElement =
| DropDown of string list
| TextInput of string option
| Slider of int * int
let createFormElement formElementType : UserInteraction<FormElement> =
match formElementType with
| FormElementType.DropDown ->
createDropDown
| FormElementType.TextInput ->
createTextInput
| FormElementType.Slider ->
createSlider
And then the new element can be added to a collection:
let form = Form.append formElement form
I am trying to find an elegant way of assigning keys to symbols without having to do something like the following.
let [<Literal>] North = ConsoleKey.UpArrow // etc.
I'd rather do something like this, using only one attribute. Is there any way I can do that?
[<Literal>]
type Direction =
| North of ConsoleKey.UpArrow
| East of ConsoleKey.RightArrow
| South of ConsoleKey.DownArrow
| West of ConsoleKey.LeftArrow
Assuming your aim is to use these in a pattern match, here is one way to do it:
// Use a type alias to shorten the name for ConsoleKey
type Key = ConsoleKey
// Create a general purpose active pattern that simply tests for equality
let (|Is|_|) a b = if a = b then Some () else None
// This is how you would use it
let describeMovement key =
match key with
| Is Key.UpArrow -> "up"
| Is Key.RightArrow -> "right"
| Is Key.DownArrow -> "down"
| Is Key.LeftArrow -> "left"
| _ -> "invalid"
Is it possible to add constant field values to F# discriminated unions?
Can I do something like this?
type Suit
| Clubs("C")
| Diamonds("D")
| Hearts("H")
| Spades("S")
with
override this.ToString() =
// print out the letter associated with the specific item
end
If I were writing a Java enum, I would add a private value to the constructor like so:
public enum Suit {
CLUBS("C"),
DIAMONDS("D"),
HEARTS("H"),
SPADES("S");
private final String symbol;
Suit(final String symbol) {
this.symbol = symbol;
}
#Override
public String toString() {
return symbol;
}
}
Just for completeness this is what is meant:
type Suit =
| Clubs
| Diamonds
| Hearts
| Spades
with
override this.ToString() =
match this with
| Clubs -> "C"
| Diamonds -> "D"
| Hearts -> "H"
| Spades -> "S"
The closest thing to your requirement is F# enums:
type Suit =
| Diamonds = 'D'
| Clubs = 'C'
| Hearts = 'H'
| Spades = 'S'
let a = Suit.Spades.ToString("g");;
// val a : string = "Spades"
let b = Suit.Spades.ToString("d");;
// val b : string = "S"
The problem with F# enums is non-exhaustive pattern matching. You have to use wildcard (_) as the last pattern when manipulating enums. Therefore, people tend to prefer discriminated unions and write explicit ToString function.
Another solution is to make a mapping between constructors and corresponding string values. This is helpful in case we need to add more constructors:
type SuitFactory() =
static member Names = dict [ Clubs, "C";
Diamonds, "D";
Hearts, "H";
Spades, "S" ]
and Suit =
| Clubs
| Diamonds
| Hearts
| Spades
with override x.ToString() = SuitFactory.Names.[x]
Pretty sure you can't, but is trivial to write a function that pattern matches and then compose the two things