When asking Agda to normalize test on the following program:
data Bool : Set where
T : Bool
F : Bool
{-# BUILTIN BOOL Bool #-}
{-# BUILTIN TRUE T #-}
{-# BUILTIN FALSE F #-}
postulate String : Set
postulate primStringEquality : String → String → Bool
{-# BUILTIN STRING String #-}
test : Bool
test = primStringEquality "bar" "foo"
It returns primStringEquality "bar" "foo" instead of F. Why?
It's primitive for equality instead of postulate. We also have to declare BUILTIN STRING before the primitives.
postulate String : Set
{-# BUILTIN STRING String #-}
primitive primStringEquality : String → String → Bool
Related
I have code generating this warning.
There are a few SO related posts, the closest is this one: This construct causes code to be less generic than indicated by the type annotations
but I don't see where it applies because my code is already in a function
so, the code in question is very simple:
let exists (key: 'a) =
r.Exists(string key)
let set (key: 'a) value =
r.Set((string key), value)
let get (key: 'a) =
r.Get(string key)
let setDefault (key: 'a) value =
if not (exists key) then
set key value
what I am trying to achieve is allow passing different enums, strings or even ints as a key, and, whatever the type passed, it would be converted to string (within reason obviously)
but when I use that code with an enum, I get the warning in the title.
So, I have two questions:
I don't really understand the warning. Can someone explain it to me?
How can I achieve passing various enums, or string and make a string key out of them?
You can reproduce this warning with an extremely simple test case, clearing up some of the noise from your example:
let f (x: 'a) =
string x
Looking at this, you may be confused, because the type of the string function is 'T -> string, but it's not that simple. To understand what's happening, you have to look at the implementation of the string function in FSharp.Core:
let inline anyToString nullStr x =
match box x with
| null -> nullStr
| :? System.IFormattable as f -> f.ToString(null,System.Globalization.CultureInfo.InvariantCulture)
| obj -> obj.ToString()
[<CompiledName("ToString")>]
let inline string (value: ^T) =
anyToString "" value
// since we have static optimization conditionals for ints below, we need to special-case Enums.
// This way we'll print their symbolic value, as opposed to their integral one (Eg., "A", rather than "1")
when ^T struct = anyToString "" value
when ^T : float = (# "" value : float #).ToString("g",CultureInfo.InvariantCulture)
when ^T : float32 = (# "" value : float32 #).ToString("g",CultureInfo.InvariantCulture)
when ^T : int64 = (# "" value : int64 #).ToString("g",CultureInfo.InvariantCulture)
when ^T : int32 = (# "" value : int32 #).ToString("g",CultureInfo.InvariantCulture)
when ^T : int16 = (# "" value : int16 #).ToString("g",CultureInfo.InvariantCulture)
when ^T : nativeint = (# "" value : nativeint #).ToString()
when ^T : sbyte = (# "" value : sbyte #).ToString("g",CultureInfo.InvariantCulture)
when ^T : uint64 = (# "" value : uint64 #).ToString("g",CultureInfo.InvariantCulture)
when ^T : uint32 = (# "" value : uint32 #).ToString("g",CultureInfo.InvariantCulture)
when ^T : int16 = (# "" value : int16 #).ToString("g",CultureInfo.InvariantCulture)
when ^T : unativeint = (# "" value : unativeint #).ToString()
when ^T : byte = (# "" value : byte #).ToString("g",CultureInfo.InvariantCulture)
This is using statically-resolved type parameters and using an explicit implementation for each of the listed types, so it is not really as generic as it seems from the type signature. In your case, what's happening is that it's inferring the most compatible type, and because your function is just typed as 'a, it's picking obj. So, because you're calling string and your input parameter is being forced into one of the types that the string function actually handles (which is actually in anyToString), and that's obj.
To make it work in your real-world scenario is actually pretty simple: Just make your functions inline and don't put a type on the parameter at all:
let inline exists key =
r.Exists(string key)
This will infer the type for the parameter and call the right version of string, and that will work with pretty much anything you want to pass it, including your enums.
The issue is from using string. If you look at the source for string, you'll see that it's inline, which means the compiler needs to determine the type at compile time. In your case, that means the generic type has to be resolved before string can be called, which in turn forces the compiler to pick something that will work - in this case, obj.
There are two simple ways to work around this - first, you can make your functions inline, which allows the compiler to defer this until the function using your string gets used. This will work in many cases, but can also potentially "push this off" to the consumer of your API later if they do the same thing you're doing. This would look like:
let inline set (key: 'a) value =
r.Set((string key), value)
The other option is to avoid the string operator, and use the fact that all objects in .NET include ToString, and call that instead:
let set (key: 'a) value =
r.Set(key.ToString()), value)
Either approach will avoid the warnings and keep the functions generic.
I'm trying to write a parser in Haskell.
This parser take a string (example: "abc def") in parameter and return a Maybe (String, String).
Maybe (String, String)
First String get characters while it's number or letter.
Second String get the rest
In this example, I want to return Maybe ("abc", " def").
parseString :: String -> Maybe (String, String)
parseString "" = Nothing
parseString expr = case isString expr of
Just (char, rest) -> fmap (char:) (parseString rest)
Nothing -> Just ("", expr)
isString return :
Maybe (Char, String) -> Char = first character, String = rest / Nothing if isn't a letter or digit.
The problem, I can not return the rest of my String in the maybe.
The issue seems to be in
fmap (char:) (parseString rest)
Now, (char:) is a function String -> String, so fmap (char:) becomes Maybe String -> Maybe String (or its generalization to another functor). However, parseString rest is not a Maybe String, it is a Maybe (String, String).
So, we need to adapt (char:) to work on the first component of that pair. I'd try
fmap (\(res,rest2) -> (char:res, rest2)) (parseString rest)
(By importing first from Data.Bifunctor or Control.Arrow, that can be written as fmap (first (char:)) (parseString rest), but that's not that important.)
I'm using the below bit of code
// Neat method of finding the TryParse method for any type that supports it.
// See https://stackoverflow.com/a/33161245/158285
let inline tryParseWithDefault (defaultVal:'a) text : ^a when ^a : (static member TryParse : string * ^a byref -> bool) =
let r = ref defaultVal
if (^a : (static member TryParse: string * ^a byref -> bool) (text, &r.contents))
then !r
else defaultVal
but I notice that the type constraint
^a : (static member TryParse : string * ^a byref -> bool
is used twice. Is there any way to do the following
constraint Parsable a = ( a : ^a : (static member TryParse : string * ^a byref -> bool)
and use Parsable like
// Neat method of finding the TryParse method for any type that supports it.
// See https://stackoverflow.com/a/33161245/158285
let inline tryParseWithDefault (defaultVal:'a) text : Parsable =
let r = ref defaultVal
if (^a : (Parsable) (text, &r.contents))
then !r
else defaultVal
As the existing answer says, you do not explicitly need to repeat the constraint in the type signature because the F# compiler can infer it. One more way of further factoring out the code that involves the type constraint would be to just have tryParse function which invokes the TryParse method (and has the type constraint) and then call this function from your tryParseWithDefault.
This way, you separate the "core" logic of invoking the member from any extra logic. When you do this, you again don't need to repeat the constraint, because the compiler infers it:
let inline tryParse text =
let mutable r = Unchecked.defaultof<_>
(^a : (static member TryParse: string * ^a byref -> bool) (text, &r)), r
let inline tryParseWithDefault (defaultVal:'a) text =
match tryParse text with
| true, v -> v
| _ -> defaultVal
There is no way I know of, however, you can simplify the function by letting F# infer the signature:
let inline tryParseWithDefault defaultVal text =
let r = ref defaultVal
if (^a : (static member TryParse: string * ^a byref -> bool) (text, &r.contents))
then !r
else defaultVal
Given the following code...
type IMyInterface =
abstract BoolA : bool
abstract BoolB : bool
let myFn _boolVal (_i: IMyInterface) = if _boolVal then _i.BoolA else _i.BoolB
let myFnTrue = myFn true
let myFnFalse = myFn false
... Intellisense complains, and the compiler fails, if I create a signature file with this in it:
type IMyInterface =
abstract BoolA : bool
abstract BoolB : bool
val myFnTrue : (IMyInterface -> bool)
val myFnFalse : (IMyInterface -> bool)
The error is Error 10 Module 'MyModule' contains val myFnTrue : ('_a -> bool) when '_a :> MyModule.IMyInterface but its signature specifies val myFnTrue : (MyModule.IMyInterface -> bool) The types differ. (A similar error is reported for myFnFalse.)
I feel like an idiot, not being able to figure this out. What am I doing wrong? (Bracing for the "duh" answer...)
In your signature file, myFnTrue and myFnFalse have the signature IMyInterface -> bool but in your implementation 'a -> bool with the constraint 'a :> IMyInterface (due to automatic generalization), that is, the implementation is generic and the signature is not.
The simplest solution is changing your implementation to this:
let myFnTrue i = myFn true i
let myFnFalse i = myFn false i
How do I convert a float to a string in F#. I'm looking for a function with this signature:
float -> string
As others pointed out, there are a few options. The two simplest are calling ToString method and using string function. There is a subtle difference between the two that you should be aware of. Here is what they do on my system:
> sprintf "%f" 1.2;;
val it : string = "1.200000"
> string 1.2;;
val it : string = "1.2"
> 1.2.ToString();;
val it : string = "1,2"
The first two are different, but both make sense, but why the heck did the last one return "1,2"?
That's because I have Czech regional settings where decimal point is written as comma (doh!) So, the string function uses invariant culture while ToString uses current culture (of a thread). In some weird cultures (like Czech :-)) this can cause troubles! You can also specify this explicitly with the ToString method:
> 1.2.ToString(System.Globalization.CultureInfo.InvariantCulture);;
val it : string = "1.2"
So, the choice of the method will probably depend on how you want to use the string - for presentation, you should respect the OS setting, but for generating portable files, you probably want invariant culture.
> sprintf "%f";;
val it : (float -> string) = <fun:it#8>
Use the 'string' function.
string 6.3f
string;;
val it : (obj -> string) = <fun:it#1>
Just to round out the answers:
(fun (x:float) -> x.ToString())
:)