How to define and use % as a prefix operator? - f#

type T() =
static member (~%)(t : T) = t
let t = T()
let t' = %t // FAILS
The error message says t was expected to be of type Quotation.Expr<'a>.
% is a supposedly valid prefix operator, but is it possible to actually use it?

The reason why you are seeing this behavior is because F# does not define (~%) with static constraints like most top-level operators. It is defined as a function Quotations.Expr<'a> -> 'a. Hence, the (~%) function (which is an alias for op_Splice) you defined on type T is not resolved by uses of the top-level (~%) operator.
You can see this by the following FSI interaction:
> <# (~%) #>;;
<# (~%) #>;;
^^^^^^^^^^
C:\Users\Stephen\AppData\Local\Temp\stdin(5,1): error FS0030: Value restriction. The value 'it' has been inferred to have generic type
val it : Expr<(Expr<'_a> -> '_a)>
Either define 'it' as a simple data term, make it a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation.
Thus if we redefine the top-level (~%) operator as follows, then your example will compile without error:
let inline (~%) (x : ^a) = (^a : (static member op_Splice : ^a -> 'b) (x))
but do note that quotation splicing will no longer work:
let x = <# 3 #>
<# %x #>
----^
error FS0001: The type 'Expr<int>' does not support the operator '~%'
that's because the original definition of (~%) is treated specially by the compiler for quotation splicing. Indeed, you can see in the Expr and Expr<'T> signatures that those types do not define any operators at all, let alone op_Splice.
You can see similar results with && and || infix operators. Which can be redefined (mapping to op_BooleanAnd and op_BooleanOr), but unless they are, they are treated specially by the compiler.

I'm not exactly sure why the % operator behaves like this, but you can redefine it using global let binding:
let (~%) a = -a
%10
If the operator cannot be defined as static member (I'm not sure if that's the case, or if I'm just missing something), you can still define an inline definition that invokes some static member of an object. This should give you essentially the same functionality:
// Instead of defining static member '%', we define static member 'Percent'
type T() =
static member Percent(t : T) = t
// Inline definition of '~%' that calls the static member 'Percent' of an object
let inline (~%) (x : ^T) = (^T : (static member Percent : ^T -> 'R) (x))
// Now you can use the '%t' syntax to invoke the static member
let t = T()
let t' = %t
Background: In F# quotation code, it is used for "splicing" of expressions into another expression (to build an expression that is composed from another, previously defined expression). The error message suggests that the compiler did not see your definition.
let two = <# 2 #>
let oneAndTwo = <# 1 + %two #>

Related

A function that accepts multiple types

I am fairly new to f#, but I want to know if it is possible to make a function that accepts multiple types of variables.
let add x y = x + y
let integer = add 1 2
let word = add "He" "llo"
Once a function use a type of variable it cannot accept another one.
You need to read about statically resolved type parameters and inline functions. It allows to create functions which may take any type that supports operation and/or have member. So your add function should be defined this way:
let inline add x y = x + y
Don't overuse inlined functions because their code inlined in call site and may increase assembly size, but may increase performance (test each case, don't make predictions!). Also inlined function are supported only by F# compiler and may not work with other languages (important when designing libraries).
Example of SRTP magic:
let inline (|Parsed|_|) (str: string) =
let mutable value = Unchecked.defaultof<_>
let parsed = ( ^a : (static member TryParse : string * byref< ^a> -> bool) (str, &value))
if parsed then
Some value
else
None
match "123.3" with
| Parsed 123 -> printfn "int 123"
| Parsed 123.4m -> printfn "decimal 123.4"
| Parsed 123.3 -> printfn "double 123.3"
// | Parsed "123.3" -> printfn "string 123.3" // compile error because string don't have TryParse static member
| s -> printfn "unmatched %s" s

Can I reprogram op_Equals in F#

I'm doing a fun project in F#, which is a DSL for Camel.Net.
At some point, I want to check conditions. But the conditions entered by the programmer should evaluate to an object tree. So I want the experssion "a = b" evaluate to "SomeType.Equals(a,b)"
Is that even possible in F#?
I have this:
type Macro =
| Header of string
| XPath of string
| Const of string
| Func of (Message -> string)
with
static member (=) (l:Macro, r:Macro) = Equals(l,r)
static member (=) (l:Macro, r:string) = Equals(l,Const(r))
and Comparison =
| Equals of Macro * Macro
Now everything in "Macro" will work as "Macro.Func" - with "Func"; a function is executed with "Message" as input param and will output the string. So the Equals(a,b) will evaluate to a string comparison during runtime.
But this code has a problem. Operator (=) does compile (it has a warning), but it can't be used as I would like.
This does not compile in the fsi:
let c1 = Header("property") = "somevalue"
I did read another question about this topic, and a bit more.
It does not answer my question.
[<NoEquality; NoComparison>] - completely shuts off the (=) operator.
[<CustomEquality; CustomComparison>] - wants you to implement an (=) operator which returns bool.
Is it even possible in F# what I want? And assuming that I can find a way, does match x with still work?
Sure, I did this reimplement to the operator in terms of System.IEquatable<T> for performance reasons:
#nowarn "86" // F# doesn't like it when you do this
[<AutoOpen>]
module FastEquals =
let inline eq<'a when 'a :> System.IEquatable<'a>> (x:'a) (y:'a) = x.Equals y
let inline (=) x y = eq x y
let inline (<>) x y = not (eq x y)
Just an example, you'll need to adapt for your own purposes.
Thanks to Asik's answer above, in combination with a reread of this post:
This works in the fsi:
type Message = class end
type Macro =
| Header of string
| XPath of string
| Const of string
| Func of (Message -> string)
type Comparison =
| Equals of Macro * Macro
type Operators = Operation with
static member CompareEquals (Operation, l:Macro, r:Macro) = Equals(l,r)
static member CompareEquals (Operation, l:Macro, r:string) = Equals(l,Const(r))
#nowarn "0086" "0064"
let inline (=) (l:'N) (r:'M) = ((^T or ^N or ^M) : (static member CompareEquals : ^T * ^N * ^M -> _) (Operation, l, r))
let c1 = Header("property1") = Header("property2")
let c2 = Header("property") = "somevalue"
Note that it does not work when the static "CompareEquals" methods are located in the "Macro" type.
If you look at the signature of op_Equals:
val inline ( = ) :
l: ^N -> r: ^M -> 'a
when (Operators or ^N or ^M) : (static member CompareEquals : Operators * ^N * ^M -> 'a)
That is a really weird syntax. I don't understand the part after "when". It works, that counts.

Resolve operator conflicts on similar generic types

I'm using a third party library (Sauve.IO) which defines the standard bind operator >>= :
val inline (>>=) : first:('T -> Async<'U option>) -> second:('U -> Async<'V option>) -> input:'T -> Async<'V option>
I also have an internal library that would also like to define the operator over the type signature
Async<Response<'a>> -> ('a -> Async<Response<'b>>) -> Async<Response<'b>>
What is the cleanest way to use these two functions in the same namespace/module without running afoul of the restriction on overloading inline functions ?
How about renaming Suave's operator to some other infix operator?
let (>=>) = Suave.(>>=)
Judging from the signature, it looks like it is not bind anyway,
but actually Kleisli composition.
You may be able to leverage F#'s statically resolved ad-hoc polymorphism: hide the qualified operator invocation behind a separate, overloaded operator; then define yet another, inlined operator for actual use.
type Foo = Foo with
static member ($) (_ : Foo, first : _ -> Async<_ option>) =
fun second value -> Module1.(>>=) first second value
static member ($) (_ : Foo, arg1 : Async<Response<_>>) =
Module2.(>>=) arg1
let inline (>>=) arg1 arg2 = (Foo $ arg1) arg2
Do both operators have the same name (>>=) ?
If so I assume that Suave's operator came with it's own module or namespace?
In this case you can qualify their operator appending their module/namespace name like this Suave.(>>=) but in this case you have to call it as usual function. Here is simplified example:
module Suave =
let inline (>>=) a b = a + 2 * b
module Mine =
open Suave
let (>>=) a b = a - 3 * b
let r1 = Suave.(>>=) 1 3
let r2 = 1 >>= 3
Result:
val r1 : int = 7
val r2 : int = -8

F# type constraints and overloading resolution

I am trying to emulate a system of type classes in F#; I would like to create pair printer which automatically instantiates the right series of calls to the printing functions. My latest try, which is pasted here, fails miserably since F# cannot identify the right overload and gives up immediately:
type PrintableInt(x:int) =
member this.Print() = printfn "%d" x
let (!) x = PrintableInt(x)
type Printer() =
static member inline Print< ^a when ^a : (member Print : Unit -> Unit)>(x : ^a) =
(^a : (member Print : Unit -> Unit) x)
static member inline Print((x,y) : 'a * 'b) =
Printer.Print(x)
Printer.Print(y)
let x = (!1,!2),(!3,!4)
Printer.Print(x)
Is there any way to do so? I am doing this in the context of game development, so I cannot afford the runtime overhead of reflection, retyping and dynamic casting: either I do this statically through inlining or I don't do it at all :(
What you're trying to do is possible.
You can emulate typeclasses in F#, as Tomas said maybe is not as idiomatic as in Haskell. I think in your example you are mixing typeclasses with duck-typing, if you want to go for the typeclasses approach don't use members, use functions and static members instead.
So your code could be something like this:
type Print = Print with
static member ($) (_Printable:Print, x:string) = printfn "%s" x
static member ($) (_Printable:Print, x:int ) = printfn "%d" x
// more overloads for existing types
let inline print p = Print $ p
type Print with
static member inline ($) (_Printable:Print, (a,b) ) = print a; print b
print 5
print ((10,"hi"))
print (("hello",20), (2,"world"))
// A wrapper for Int (from your sample code)
type PrintableInt = PrintableInt of int with
static member ($) (_Printable:Print, (PrintableInt (x:int))) = printfn "%d" x
let (!) x = PrintableInt(x)
let x = (!1,!2),(!3,!4)
print x
// Create a type
type Person = {fstName : string ; lstName : string } with
// Make it member of _Printable
static member ($) (_Printable:Print, p:Person) = printfn "%s, %s" p.lstName p.fstName
print {fstName = "John"; lstName = "Doe" }
print (1 ,{fstName = "John"; lstName = "Doe" })
Note: I used an operator to avoid writing the constraints by hand, but in this case is also possible to use a named static member.
More about this technique here.
What you're trying to do is not possible (edit: apparently, it can be done - but it might not be idiomatic F#), because the constraint language cannot capture the constraints you need for the second Print operation. Basically, there is no way to write recursive constraints saying that:
Let C be a constraint specifying that the type either provides Print or it is a two-element tuple where each element satisfies C.
F# does not support type-classes and so most of the attempts to emulate them will (probably) be limited in some way or will look very unnatural. In practice, instead of trying to emulate solutions that work in other languages, it is better to look for an idiomatic F# solution to the problem.
The pretty printing that you're using as a sample would be probably implemented using Reflection or by wrapping not just integers, but also tuples.

How to define compile-time type casting operators in F#?

Given:
let ab = ArgumentBlockSettingStore()
let a = ab :> ISettingStore
Is there a way to define a prefix operator (~~) so that
let ab, a = ~~ArgumentBlockSettingStore() : _ * ISettingStore
becomes possible?
I think you're hitting the compiler restrictions that you mentioned in the comment - you can't write the ~~ operator in a fully generic and safe way meaning that it will only allow casting to an interface that the argument implements. You can define an operator that will cast to any other type, but that's less safe:
let inline (~~) (a:^T) : ^T * ^R = a, (box a) :?> ^R
let reader, (disposable:IDisposable) = ~~(new StreamReader("..."))
I used inline, because the operator is quite simple, but it works the same way with normal operators. This compiles even if you use Random in the type annotation for disposable, which is a bit unfortunate.

Resources