The ocaml manual chapter 8 "language extensions" describes "inline records" (8.17):
The arguments of sum-type constructors can now be defined using the same syntax as records. Mutable and polymorphic fields are allowed. GADT syntax is supported. Attributes can be specified on individual fields. [...]
I am looking for that with polymorphic variants:
# type a = B of {x:int; mutable y:int} ;;
type a = B of { x : int; mutable y : int; }
# type b = `A of {u:int; mutable v:int} ;;
Line 1, characters 9-10:
Error: Syntax error
But that does not work, so right now I use an explicit auxiliary record type instead...
As I understand it now, this both takes more memory and is somewhat slower.
Can I get this cool feature with polymorphic variants, too?
In the cases of ordinary constructors, the compiler can use the type definition to distinguish between:
type t = A of int * int | B
let f = function
| A (_,y) -> y
| B -> 0
and
type 'a t = A of 'a | B
let f = function
| A (_,y) -> y
| B -> 0
Thus, it is possible to optimize the first
A (_,y) -> y
into "access the second field of the block` while still compiling the second case
A (_,y) -> y
to "access the tuple in the first field of the block, and then access the second field of the block".
For polymorphic variants, it is not possible to rely on the non-existing type definition to distinguish between those two solutions. Consequently, their memory representation must be uniform. This means that polymorphic variants always take one argument, and it is not really useful to label each argument of the constructor when there is only one argument.
This is why inline records cannot be combined with polymorphic variants.
Related
I'm reading lambdasoup/soup.ml at master · aantron/lambdasoup · GitHub but I don't understand the syntax.
and 'a node =
{mutable self : 'b. 'b node option;
mutable parent : general node option;
values : [ `Element of element_values
| `Text of string
| `Document of document_values ]}
I don't understand 'b. 'b node option, if it was * it would be a tuple but it's the first time I see with . Also why the back-tic in the branches (e.g. `Element)?
The type 'a . type is a type that is explicitly polymorphic in 'a. So your example 'b . 'b node option is explcitly a field whose contents are polymorphic. In other words, any value assigned to the field must itself be polymorphic.
Here's an example with list rather than node:
type a = { mutable self : 'b. 'b list option; }
# let x = { self = None };;
val x : a = {self = None}
# x.self <- None;;
- : unit = ()
# x.self <- Some [];;
- : unit = ()
# x.self <- Some [3];;
Error: This field value has type int list option
which is less general than 'b. 'b list option
#
You can assign None to x.self because None is polymorphic (its type is 'a option, which works for any option type). You can assign Some [] to x.self because it's also polymorphic (its type is 'a list option, which works for any optional list). But you can't assign Some [3] to x.self because its type is int list option; in other words, it's not polymorphic.
You can find a discussion of explicitly polymorphic types in Section 5.2.1 of the OCaml manual.
Variant values with leading backquote like `A or `B are so-called polymorphic variants. This is a different feature than the usual variant types. The basic idea is that a polymorphic variant represents a value that is not necessarily part of any predefined type. The associated types are essentially sets of these values. Polymorphic variants can also be constructors as in your example type; that is, they can take an associated value. Just as you can have Some "yes", your definition allows one to have `Text "yes".
You can find some discussion of polymorphic variants in Section 7.4 of the OCaml manual (search for "polymorphic variant types").
I'm learning F#. I want to know best practices for validating input parameters. In my naivety I had thought I could do something like this:
let foo = match bar with
| <test for valid> -> bar
| _ -> "invalid"
of course that doesn't work due to mismatching types. So I'd like to see the patterns experienced F# programmers use for this sort of thing. match? If/then/else?
Something else?
You are having problems because you are trying to bind a value to something that could be two possible types depending upon program flow - that is incompatible with static typing.
If I have some value foo, it cannot be, for example, a string OR an int depending upon program flow; it must resolve to exactly one type at compile time.
You can, however, use a discriminated union that can represent several different options within a single type.
Here is a summary of the approaches for doing just that.
Result Type / Either
F# 4.1, which is currently available via nuget, introduces the Result type. You may find this type referred to as Either in other languages.
It is defined like this:
[<Struct>]
type Result<'T,'TError> =
/// Represents an OK or a Successful result. The code succeeded with a value of 'T.
| Ok of ResultValue:'T
/// Represents an Error or a Failure. The code failed with a value of 'TError representing what went wrong.
| Error of ErrorValue:'TError
If you are pre-F# 4.1 (which is very likely). You can define this type yourself, although you must remove the [<Struct>] attribute.
You can then make a tryParseFloat function:
let tryParseFloat str =
match System.Double.TryParse str with
| true, f -> Ok f
| _ -> Error <| sprintf "Supplied string (%s) is not a valid float" str
You can determine success or failure:
match tryParseFloat "0.0001" with
|Ok v -> // handle success
|Error err -> // handle error
In my opinion, this is the preferred option, especially in F# 4.1+ where the type is built in. This is because it allows you to include information relating to how and why some activity failed.
Option Type / Maybe
The option type contains either Some 'T or simply None. The option type is used to indicate the presence or absence of a value, None fills a role similar to null in other languages, albeit far more safely.
You may find this type referred to as Maybe in other languages.
let tryParseFloat str =
match System.Double.TryParse str with
| true, f -> Some f
| _ -> None
You can determine success or failure:
match tryParseFloat "0.0001" with
|Some value -> // handle success
|None -> // handle error
Composition
In both cases, you can readily compose options or results using the associated map and bind functions in the Option and Result modules respectively:
Map:
val map: mapping:('T -> 'U) -> option:'T option -> 'U option
val map : mapping:('T -> 'U) -> result:Result<'T, 'TError> -> Result<'U, 'TError>
The map function lets you take an ordinary function from 'a -> 'b and makes it operate on results or options.
Use case: combine a result with a function that will always succeed and return a new result.
tryParseFloat "0.001" |> Result.map (fun x -> x + 1.0);;
val it : Result<float,string> = Ok 1.001
Bind:
val bind: binder:('T -> 'U option) -> option:'T option -> 'U option
val bind: binder:('T -> Result<'U, 'TError>) -> result:Result<'T, 'TError> -> Result<'U, 'TError>
The bind function lets you combine results or options with a function that takes an input and generates a result or option
Use case: combine a result with another function that may succeed or fail and return a new result.
Example:
let trySqrt x =
if x < 0.0 then Error "sqrt of negative number is imaginary"
else Ok (sqrt x)
tryParseFloat "0.001" |> Result.bind (fun x -> trySqrt x);;
val it : Result<float,string> = Ok 0.0316227766
tryParseFloat "-10.0" |> Result.bind (fun x -> trySqrt x);;
val it : Result<float,string> = Error "sqrt of negative number is imaginary"
tryParseFloat "Picard's Flute" |> Result.bind (fun x -> trySqrt x);;
val it : Result<float,string> =
Error "Supplied string (Picard's Flute) is not a valid float"
Notice that in both cases, we return a single result or option despite chaining multiple actions - that means that by following these patterns you need only check the result once, after all of your validation is complete.
This avoids a potential readability nightmare of nested if statements or match statements.
A good place to read more about this is the Railway Oriented Programming article that was mentioned to you previously.
Exceptions
Finally, you have the option of throwing exceptions as a way of preventing some value from validating. This is definitely not preferred if you expect it to occur but if the event is truly exceptional, this could be the best alternative.
The basic way of representing invalid states in F# is to use the option type, which has two possible values. None represents invalid state and Some(<v>) represents a valid value <v>.
So in your case, you could write something like:
let foo =
match bar with
| <test for valid> -> Some(bar)
| _ -> None
The match construct works well if <test for valid> is actual pattern (e.g. empty list or a specific invalid number or a null value), but if it is just a boolean expression, then it is probably better to write the condition using if:
let foo =
if <test for valid> bar then Some(bar)
else None
You could do something along this lines
type Bar =
| Bar of string
| Foo of int
let (|IsValidStr|_|) x = if x = Bar "bar" then Some x else None
let (|IsValidInt|_|) x = if x = Foo 0 then Some x else None
let foo (bar:Bar) =
match bar with
| IsValidStr x -> Some x
| IsValidInt x -> Some x
| _ -> None
That is you could use active patterns to check for the actual business rules and return an Option instance
Based on what the OP wrote in the comments:
You would define a type as in the post that Fyodor linked, that captures your two possible outcomes:
type Result<'TSuccess,'TFailure> =
| Success of 'TSuccess
| Failure of 'TFailure
Your validation code becomes:
let checkBool str =
match bool.TryParse str with
| true, b -> Success b
| _ -> Failure ("I can't parse this: " + str)
When using it, again use match:
let myInput = "NotABool"
match checkBool myInput with
| Success b -> printfn "I'm happy: %O" b
| Failure f -> printfn "Did not like because: %s" f
If you only would like to continue with valid bools, your code can only fail on invalid arguments, so you would do:
let myValidBool =
match checkBool myInput with
| Success b -> b
| Failure f -> failwithf "I did not like the args because: %s" f
Currently, I'm trying to teach myself some F# by making an application that consists of a C# GUI layer and an F# business layer. In the GUI layer, the user will at some point have to make a choice by selecting a value that is part of a simple enum, e.g. selecting either of the following:
enum {One, Two, Three}
I have written a function to translate the enum value to an F# discriminated union
type MyValues =
| One
| Two
| Three
Now I have to translate back, and am already tired of the boilerplate code. Is there a generic way to translate my discriminated union to the corresponding enum, and vice versa?
Cheers,
You can also define the enum in F# and avoid doing conversions altogether:
type MyValues =
| One = 0
| Two = 1
| Three = 2
The = <num> bit tells the F# compiler that it should compile the type as a union. When using the type from C#, this will appear as a completely normal enum. The only danger is that someone from C# can call your code with (MyValues)4, which will compile, but it will cause incomplete pattern match exception if you are using match in F#.
Here are generic DU/enum converters.
open Microsoft.FSharp.Reflection
type Union<'U>() =
static member val Cases =
FSharpType.GetUnionCases(typeof<'U>)
|> Array.sortBy (fun case -> case.Tag)
|> Array.map (fun case -> FSharpValue.MakeUnion(case, [||]) :?> 'U)
let ofEnum e =
let i = LanguagePrimitives.EnumToValue e
Union.Cases.[i - 1]
let toEnum u =
let i = Union.Cases |> Array.findIndex ((=) u)
LanguagePrimitives.EnumOfValue (i + 1)
let du : MyValues = ofEnum ConsoleColor.DarkGreen
let enum : ConsoleColor = toEnum Three
It maps the DU tag to the enum underlying value.
I'm trying to make a function that defines a vector that varies based on the function's input, and set! works great for this in Scheme. Is there a functional equivalent for this in OCaml?
I agree with sepp2k that you should expand your question, and give more detailed examples.
Maybe what you need are references.
As a rough approximation, you can see them as variables to which you can assign:
let a = ref 5;;
!a;; (* This evaluates to 5 *)
a := 42;;
!a;; (* This evaluates to 42 *)
Here is a more detailed explanation from http://caml.inria.fr/pub/docs/u3-ocaml/ocaml-core.html:
The language we have described so far is purely functional. That is, several evaluations of the same expression will always produce the same answer. This prevents, for instance, the implementation of a counter whose interface is a single function next : unit -> int that increments the counter and returns its new value. Repeated invocation of this function should return a sequence of consecutive integers — a different answer each time.
Indeed, the counter needs to memorize its state in some particular location, with read/write accesses, but before all, some information must be shared between two calls to next. The solution is to use mutable storage and interact with the store by so-called side effects.
In OCaml, the counter could be defined as follows:
let new_count =
let r = ref 0 in
let next () = r := !r+1; !r in
next;;
Another, maybe more concrete, example of mutable storage is a bank account. In OCaml, record fields can be declared mutable, so that new values can be assigned to them later. Hence, a bank account could be a two-field record, its number, and its balance, where the balance is mutable.
type account = { number : int; mutable balance : float }
let retrieve account requested =
let s = min account.balance requested in
account.balance <- account.balance -. s; s;;
In fact, in OCaml, references are not primitive: they are special cases of mutable records. For instance, one could define:
type 'a ref = { mutable content : 'a }
let ref x = { content = x }
let deref r = r.content
let assign r x = r.content <- x; x
set! in Scheme assigns to a variable. You cannot assign to a variable in OCaml, at all. (So "variables" are not really "variable".) So there is no equivalent.
But OCaml is not a pure functional language. It has mutable data structures. The following things can be assigned to:
Array elements
String elements
Mutable fields of records
Mutable fields of objects
In these situations, the <- syntax is used for assignment.
The ref type mentioned by #jrouquie is a simple, built-in mutable record type that acts as a mutable container of one thing. OCaml also provides ! and := operators for working with refs.
Ok, so let's say I have a type defined like so:
type Foo =
| Bar of (SomeType * SomeType * SomeType * SomeType)
| ...(other defs)
so I have a Bar, that is basically a tuple of 4 SomeTypes. I want to access individual members of the tuple. I tried this:
let Bar (one, two, three, four) = someBar
But when I try to refer to one, or two later on in the function it says that "the value or constructor is not defined" So it is not treating the assignment as expected. What is the correct way to do this?
Also, if i try:
let one,two,three,four = someBar
It complains:
someBar was expected to have type 'a*'b*'c*'d but here has type Foo
thanks,
You just need to add another set of parentheses:
let (Bar(one,two,three,four)) = someBar
As Stephen points out, without the additional parens the compiler treats this line of code as the definition of a new function called Bar. He is also right that pattern matching would probably be more appropriate if there are other cases in the discriminated union.
Given
type Foo =
| Bar of (int * int * int * int)
| Bar2 of string
let x = Bar(1,2,3,4)
let Bar(y1,y2,y3,y4) = x
the last let binding is interpreted as a function, Bar : 'a * 'b * 'c * 'd -> Foo. The function name is throwing you off, since it is the same as your union case, but it's the same as if you had defined let some_func_takes_a_tuple_and_returns_x (y1,y2,y3,y4) = x.
I think you may have to be a little more verbose:
let y1,y2,y3,y4 =
match x with
| Bar(y1,y2,y3,y4) -> y1,y2,y3,y4
Which is fair enough, since unlike tuple decomposition let bindings, decomposing Bar here is dangerous because the match is incomplete (x could actually be some other Foo case, like Bar2).
Edit
#kvb knows the secret to making this work as you expect!