Let's say that for some strange reason I want to have this function:
let (~-) (str:string) = 42
So I can do something like this and get 42 as result:
-"test"
val it : int = 42
Which is fine. But now when I do:
let a = 100
-a
I get:
error FS0001: This expression was expected to have type
string
but here has type
int
Any idea why is this happening?
When you define operators using let, the new definition hides all previous definition of the operator. So in your example, you are hiding the default implementation of the unary minus (which works for numbers) and replacing it with a new operator that only works on strings.
It is not easy to re-define overloaded operators on built-in types. If you need that, it is probably better idea to avoid using operators (just use a function). However, if you want to provide an overloaded operator for a custom type, you can do this by adding operator as a static member:
type MinusString(s:string) =
member x.Value = s
/// Provide unary minus for MinusString values
static member (~-) (ms:MinusString) =
MinusString("-" + ms.Value)
-(MinusString "hi") // Returns "-hi"
If you really want to redefine built-in operator like unary minus and make it work on string, then there is actually a way to do this using a trick described in earlier SO answers. However, I would only use this if you have a good reason.
Simply, you overwrote the minus operator with one that takes a string and returns an int, then tried to apply it to an int, which it can't do anymore.
Related
I have read Kotlin docs as well as the wikipedia links (https://en.wikipedia.org/wiki/Infix_notation#:~:text=Infix%20notation%20is%20the%20notation,plus%20sign%20in%202%20%2B%202), but unfortunately I am still unable to make use of this notation in my code.
Could someone please let me know, how can I use it?
Before jumping on to the code, let’s look at the rules of it’s usage (From the docs: https://kotlinlang.org/docs/functions.html#infix-notation):
Infix notation must be used with member functions or extension functions
They must have a single parameter
The parameter must not accept variable number of arguments and must have no default value.
Keeping these pointers in mind, you can achieve the following:
fun Int.add(x: Int) = this.plus(x) //This is a simple Extension function without infix notation
infix fun Int.subtract(x: Int) = this.minus(x) //Added infix notation here
fun main() {
val sum = 10.add(20)
println(sum) //prints 30
val sub = 100 subtract 30 //Notice that there is no dot(.) and parenthesis
println(sub) //prints 70
}
This is how we can use infix notations and get rid of the dots(.) and parenthesis and they will work the same.
This increases code readability.
I've defined a polymorphic binary relation type (a class) in Dafny:
class binRel<S,T>
The actual declaration is:
class binRel<S(!new,==),T(!new,==)>.
I'd like to add a new type constraint: that types S and T should implement a "show" operation (returning a string).
My reading of the Dafny Reference Manual suggests Dafny supports only a few built-in type constraints: ==, and evidently !new, and that there's no way to require that type support, e.g., some particular trait.
Perhaps I'm wrong and that updates more recent than the reference manual have provided such capabilities. Am I in luck? If not, is there perhaps a work-around?
Correct, there are only a few built in type constraints in Dafny. There is no mechanism to require that a type extend a trait.
I'm not aware of a good work around for the object-oriented/imperative fragment of Dafny. In the pure fragment, you could work around this using first-class functions.
datatype MyPair<A,B> = MakePair(a: A, b: B)
type Show<!A> = A -> string
function ShowMyPair<A,B>(sa: Show<A>, sb: Show<B>): Show<MyPair<A,B>>
{
(p: MyPair<A,B>) => "(" + sa(p.a) + "," + sb(p.b) + ")"
}
In F# I can combine strings with the + operator as follows:
let myString = "one" + "two"
But when I create a function that will accept two arguments and apply the same operator, and I put it in a module declared ahead of its usage, F# infers the types as integers:
module StringFunctions =
let add str1 str2 =
str1 + str2
Calling the below gives me the build error, "The expressions was expected to have type 'int' but here has type 'string'":
let str3 = StringFunctions.add "three" "four"
Why does F# infer this as int? I assume that it can't be a generic method because not all types will implement the + operator, but why does it assume int?
The short version is, "Because that's how F# is designed".
The longer version is that if a function's type can't be generic (and you're correct that this one can't since not all types will necessarily inplement the + operator), then F# has to pick a real type. The most common use case for the + operator is adding integers, so F# defaults to assuming that + is the integer-addition operator unless you tell it otherwise.
One way you could tell it otherwise is to put in a type annotation:
let add (str1 : string) str2 = str1 + str2
Note that you don't have to annotate both parameters: knowing that one side of the + operator is a string is enough to let F# infer that the other side must be a string as well.
The other thing you could do is to make the function inline, which will result in two things:
F# will not compile this into a function call, but will actually insert the function's code into the calling locations, and
Because of this, the F# compiler will be able to use different + operators in different calling locations, if needed.
That is, add 3 5 would become 3 + 5 which uses the integer-addition operator, and add "foo" "bar" would become "foo" + "bar" which uses the string-addition overload of +.
The reasons why this works are gone into in more depth in questions like F# generics / function overloading syntax and Use of `inline` in F# (among others), so I won't get into them here.
I love the simplicity of types like
type Code = Code of string
But I would like to put some restrictions on string (in this case - do not allow empty of spaces-only strings). Something like
type nonemptystring = ???
type Code = Code of nonemptystring
How do I define this type in F# idiomatic way? I know I can make it a class with constructor or a restricted module with factory function, but is there an easy way?
A string is essentially a sequence of char values (in Haskell, BTW, String is a type alias for [Char]). A more general question, then, would be if it's possible to statically declare a list as having a given size.
Such a language feature is know as Dependent Types, and F# doesn't have it. The short answer, therefore, is that this is not possible to do in a declarative fashion.
The easiest, and probably also most idiomatic, way, then, would be to define Code as a single-case Discriminated Union:
type Code = Code of string
In the module that defines Code, you'd also define a function that clients can use to create Code values:
let tryCreateCode candidate =
if System.String.IsNullOrWhiteSpace candidate
then None
else Some (Code candidate)
This function contains the run-time logic that prevents clients from creating empty Code values:
> tryCreateCode "foo";;
val it : Code option = Some (Code "foo")
> tryCreateCode "";;
val it : Code option = None
> tryCreateCode " ";;
val it : Code option = None
What prevents a client from creating an invalid Code value, then? For example, wouldn't a client be able to circumvent the tryCreateCode function and simply write Code ""?
This is where signature files come in. You create a signature file (.fsi), and in that declare types and functions like this:
type Code
val tryCreateCode : string -> Code option
Here, the Code type is declared, but its 'constructor' isn't. This means that you can't directly create values of this types. This, for example, doesn't compile:
Code ""
The error given is:
error FS0039: The value, constructor, namespace or type 'Code' is not defined
The only way to create a Code value is to use the tryCreateCode function.
As given here, you can no longer access the underlying string value of Code, unless you also provide a function for that:
let toString (Code x) = x
and declare it in the same .fsi file as above:
val toString : Code -> string
That may look like a lot of work, but is really only six lines of code, and three lines of type declaration (in the .fsi file).
Unfortunately there isn't convenient syntax for declaring a restricted subset of types but I would leverage active patterns to do this. As you rightly say, you can make a type and check it's validity when you construct it:
/// String type which can't be null or whitespace
type FullString (string) =
let string =
match (System.String.IsNullOrWhiteSpace string) with
|true -> invalidArg "string" "string cannot be null or whitespace"
|false -> string
member this.String = string
Now, constructing this type naively may throw runtime exceptions and we don't want that! So let's use active patterns:
let (|FullStr|WhitespaceStr|NullStr|) (str : string) =
match str with
|null -> NullStr
|str when System.String.IsNullOrWhiteSpace str -> WhitespaceStr
|str -> FullStr(FullString(str))
Now we have something that we can use with pattern matching syntax to build our FullStrings. This function is safe at runtime because we only create a FullString if we're in the valid case.
You can use it like this:
let printString str =
match str with
|NullStr -> printfn "The string is null"
|WhitespaceStr -> printfn "The string is whitespace"
|FullStr fstr -> printfn "The string is %s" (fstr.String)
On line 5633 in prim-types.fs (v1.9.7.8) there is the following type abbreviation:
type 'T ``lazy`` = Lazy<'T>
I have a few questions about it.
What do the double backticks mean?
Is this definition equivalent to type lazy<'T> = Lazy<'T>? (If not, how is it different?)
The double back ticks are a way of allowing an F# keyword to be used as an identifier. Another example would be
let ``let`` = 42
To answer the second half of your question, generic types in F# can be specified using either the O'Caml-style syntax where the generic parameter precedes the type (e.g 'a list, int array, etc.), or the .NET-style with angle brackets (e.g. list<'a>, array<int>, etc.), so the two definitions are indeed basically equivalent (except that your version as written is syntactically invalid because lazy is a keyword). For multi-parameter generic types, the O'Caml style is deprecated and will generate a warning (e.g. let (m:(int,string) Map) = Map.empty should be rewritten as let (m:Map<int,string>) = Map.empty).