In Haskell, types can be defined to be an alias for another type. For example, I could write
type MString = Maybe String
Is it possible to have aliases like this in Agda, too? I only know of the data keyword that forces me to write a new wrapper data type with named constructors:
data MString : Set where
mstring : Maybe String → MString
where I would just like to write
data MString = Maybe String
just as in Haskell.
You can just write
MString : Set
MString = Maybe String
without any type or data keyword (the MString : Set annotation is optional in this case but recommended).
Related
In C# you can write string.Join and String.Join. But in F# you cannot write string.Join but only String.Join. Why is that? Is not string a type alias over .NET String class?
In F# string, depending on where it's used, is a type alias or a function:
string 12 // this stringifies '12'
let f (s: string) = ... // here 'string' is a type alias for 'System.String'
And so static members like Join don't sit on string. They are available via String. If you created your own alias, then you'd get access to the static members via ..
In C#, both string and String refer to the same System.String at all times.
If I have the following:
type StringList = StringList of string list
let sl = StringList [ "Hello, "; "World" ]
let length = List.length sl
then the following compiler error is thrown:
This expression was expected to have type 'a list but here has type StringList
My understanding is that StringList is an option "wrapping" string list, so how can I "unwrap" it such that I can call List methods on it?
The problem is that your StringList type is defining a new type that is a wrapper over string list. The functions that would work on string list do not work on your wrapper, because they do not know anything about it.
You could define StringList as a type alias - so rather than defining a new type, it is just a convenient name for the same thing:
type StringList = string list
let sl : StringList = [ "Hello, "; "World" ]
let length = List.length sl
The other option is to extract the string list value before calling List.length:
type StringList = StringList of string list
let stringListlength (StringList(slData)) =
List.length slData
let sl = StringList [ "Hello, "; "World" ]
stringListlength sl
In the first approach, you are just defining a name, but the compiler will not do any checks on it, so it is only useful if you want to use the name in type annotations (for example) to make them readable.
In the second approach, you are really defining a new type, so you ensure that everyone working with StringList will use the functions you define or working with it.
It is hard to say what is a good approach here, because StringList is not very good example - it does not really convey any additional information over string list.
I have declared some data types in a F# library that I want to fill from C# code. The problem I encountered is that only DU's get "exported" as a class, consider this example file Test.fs:
module Test
type SimpleType = string
type SimpleList = string list
type SimpleDU =
| A
| B
type SimpleRecord = { Text : string }
I was confused at first when just referencing the F# project wouldn't allow me use the SimpleType and SimpleList types in C#. I looked at the resulting F# library with ILDasm and found only code for the SimpleDU and SimpleRecord type which are perfectly accessible in C# code.
Is there a way to "export" non DU types so they are usable in C# or do I have to declare every non DU type as an explicit record?
The definitions of
type SimpleType = string
type SimpleList = string list
are type abbreiviations which are eliminated during type checking and do not create new types. These are described in the specifition:
8.3 Type Abbreviations
Type abbreviations define new names for other types. For example:
type PairOfInt = int * int
Type abbreviations are expanded and erased during compilation and do
not appear in the elaborated form of F# declarations, nor can they be
referred to or accessed at runtime.
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).