I'm trying to define notation for a type I defined in my OCaml project. Basically this type allows me to express either one or two values of a type and I called it maybe_pair. I'd like to be able to write some notation for defining values of this type, for example:
For a single value we could write <5> : int maybe_pair
For two values we could write <3;7> : int maybe_pair
I'm basically trying to imitate how the lists notation work, but I believe this may be impossible.
You can't get the notation you want just by defining OCaml functions. You can define < and > as infix operators (with a fixed pre-defined precedence), but you can't define them to work in pairs like parentheses.
You can get any desired syntax using the OCaml syntax extension mechanism ppx. But this is a large subject, too big for an answer here on StackOverflow (in my opinion).
You can read about PPX here: https://ocamlverse.github.io/content/ppx.html
And here: https://github.com/ocaml-ppx/ppxlib
The type below can hold either one or two values of type 'a:
type 'a maybe_pair = Single of 'a | Double of 'a * 'a
You can write a ppx-rewriter to partially achieve your goal, although the notation with angle brackes isn't supported.
I'll assume the pair is defined as follows:
(* file: pair.ml *)
type 'a maybe_pair = MkPair of 'a * 'a option [##deriving show]
The ppx extension should then look as follows:
(* file: ppx_pair.ml *)
open Ppxlib
let name = "mp"
let expand ~loc ~path:_ expr =
match expr with
| {pexp_desc = Pexp_sequence (e1,e2); _} -> [%expr Pair.MkPair ([%e e1], Some [%e e2]) ]
| e1 -> [%expr Pair.MkPair ([%e e1], None) ]
let ext =
Extension.declare name Extension.Context.expression
Ast_pattern.(single_expr_payload __)
expand
let () = Driver.register_transformation name ~extensions:[ext]
We can see it in action as follows:
let () =
let x = [%mp 1] in
Format.printf "x is %a\n" (Pair.pp_maybe_pair Format.pp_print_int) x;
let x = [%mp 1; 2] in
Format.printf "x is %a\n" (Pair.pp_maybe_pair Format.pp_print_int) x
Outputs:
x is (Pair.MkPair (1, None))
x is (Pair.MkPair (1, (Some 2)))
I've made a minimally working example project structure here:
https://gitlab.com/gopiandcode/example-ppxlib
Related
I'm a big fan of creating data structures that make representing invalid states impossible, so I wanted to ask how I could represent a non empty list in reasonml?
Since it's possible to pattern match on lists like [] and [head, ...rest] I thought it would be easy to represent a non empty list, but I haven't found a way yet.
Update: Thanks to the enlightening answers below I was able to come up with something that really strikes my tune:
module List = {
include List;
type nonEmpty('a) = ::('a, list('a));
let foldNonEmpty = (type a, fn, l: nonEmpty(a)) => switch(l) {
| [head, ...tail] => fold_left(fn, head, tail)
};
}
module Number = {
let min = List.foldNonEmpty(Pervasives.min);
let max = List.foldNonEmpty(Pervasives.max);
}
Number.min([]); // illegal :D
Number.min([1]); // legal
Don't know how you guys feel about it, but I think it's awesome. Thanks!
You can also define a new list type without GADT as:
type nonempty('a) =
| First('a)
| ::('a,nonempty('a))
Compared to the GADT solution, you lose some syntactic sugar, because the syntax
let l = [1,2,3,4]
implicitly adds a terminal [] but the [x, ...y] syntax still works
let x = [1, 2, 3, 4, ...First(5)];
let head =
fun
| [a, ...q] => a
| First(a) => a;
let tail =
fun
| [a, ...q] => Some(q)
| First(a) => None;
Otherwise, the encoding
type nonempty_2('a) = { head:'a, more:list('a) };
let x = { head:1, more:[2,3,4,5 ] };
let head = (x) => x.head;
let tail = fun
| {more:[head,...more],_} => Some({head, more})
| {more:[],_} => None;
is even simpler and does not rely on potentially surprising syntactic constructions.
EDIT: ::, the infix variant constructor
If the part of the definition with :: seems strange, it is because it is a left-over of corner case of the OCaml syntax. In Ocaml,
[x, ... l ]
is written
x :: l
which is itself the infix form of
(::)(x,l)
(This the same prefix form of standard operator : 1 + 2 can also be written as
(+)(1,2) (in Reason)
)
And the last form is also the prefix form of [x,...l] in reason.
In brief, in Reason we have
[x, ... l ] ≡ (::)(x,l)
with the OCaml syntax as the missing link between the two notations.
In other words :: is an infix constructor (and the only one). With recent enough version of OCaml, it is possible to define your own version of this infix constructor with
type t = (::) of int * int list
The same construction carries over in Reason as
type t = ::(int, list(int))
Then if you write [a, ...b] it is translated to (::)(a,b) with :: as your newly defined operator. Similarly,
[1,2,3]
is in fact a shortcut for
[1,2,3, ...[]]
So if you define both [] and ::, for instance in this silly example
type alternating('a,'b) =
| []
| ::('a, alternating('b,'a) )
/* here the element of the list can alternate between `'a` and `'b`:*/
let l = [1,"one",2,"two"]
you end up with a syntax for exotic lists, that works exactly the same as
standard lists.
You can use GADT for this use case.
(we can also add phantom type https://blog.janestreet.com/howto-static-access-control-using-phantom-types/) but it isn't mandatory
type empty = Empty;
type nonEmpty = NonEmpty;
type t('a, 's) =
| []: t('a, empty)
| ::(('a, t('a, 's))): t('a, nonEmpty);
How to use it
let head: type a. t(a, nonEmpty) => a =
fun
| [x, ..._] => x;
type idea come form https://sketch.sh/s/yH0MJiujNSiofDWOU85loX/
this is a question about ocaml lists and tuples. I have some 2-tuples of numbers (either integers or floats) and I want to convert it to a list of lists (with 2 elements). Assuming that I have defined a num type Int of int | Float of float, the conversion should give the following:
((1,1.0),(0.4,1),(0,0)) => [[Int 1;Float 1.0];[Float 0.4; Int 1];[Int 0;Int 0]]
or more precisely
let a = (1,1.0) and b = (0.4,1) and c = (0,0) in
myconversion (a,b,c) ;;
=> [[Int 1;Float 1.0];[Float 0.4; Int 1];[Int 0;Int 0]]
the point being the values a, b, c... are defined in several places in the source files (by people who use different signatures for their tuples).
The difficulty here is that I don't know the types of the elements of the 2-tuples (int or float, that varies depending on the tuple).
Your input data can't be represented in OCaml as you describe it. OCaml is strongly typed. For example, your example input list is an invalid value in OCaml:
# [(1,1.0);(0.4,1);(0,0)];;
Error: This expression has type float but an expression was expected of type
int
So what you describe as the essence of your problem (not knowing the types) is in fact not possible. You'll have to use some other method of representing the input. For example, you could just use floats for everything. Or you could use pairs of strings.
Update
The answer for the rewritten question is the same. In OCaml it's not possible not to know the type of something statically; i.e., at the time you're writing the program (unless it can be any type at all). It's not possible (or necessary) to query the type of something at runtime. So your question doesn't have an answer (at least as far as I can see).
For OCaml, you have to think with the type system rather than against it. After a while you start to really like it (or at least that's how it worked for me). I'd start by writing down the type you want your function myconverstion to have.
Update 2
I'll repeat my advice to treat your inputs as strings. Assuming you've parsed your input up into pairs of strings, here's some code that does what you want:
let myconversion coords =
let c1 s =
if String.contains s '.' then
Float (float_of_string s)
else
Int (int_of_string s)
in
let cp (a, b) = [c1 a; c1 b] in
List.map cp coords
Here's how it works for your input (reinterpreted as strings):
# myconversion [("1", "1.0"); ("0.4", "1"); ("0", "0")];;
- : fi list list = [[Int 1; Float 1.]; [Float 0.4; Int 1]; [Int 0; Int 0]]
Update 3
Here's some (crude) code that parses a file of numbers into coordinates represented as pairs of strings. It should work as long as the tuples in the input are well formed.
let coords fname =
let ic = open_in fname in
let len = in_channel_length ic in
let buf = Buffer.create 128 in
let () = Buffer.add_channel buf ic len in
let () = close_in ic in
let s = Buffer.contents buf in
let nums = Str.(split (regexp "[^0-9.]+") s) in
let rec mkcoords sofar = function
| [] | [_] -> List.rev sofar
| a :: b :: rest -> mkcoords ((a, b) :: sofar) rest
in
mkcoords [] nums
There are two distinct problems in your setup:
you don't know the type of the tuples parameters
you want to pass them as a single n-ary tuple
For problem 2, you would have to write a function for that type specifically, whereas you could mimic a type level list type by nesting couple of tuples:
myconversion a,(b,c) ;;
The reason is that with that setup, you could write a recursive polymorphic function on the type level list:
val myconversion : type a b. (a,b) -> num list
There would still be a problem on the last element though.
So, assuming that you could pass a sequence to your conversion function, and have it process elements of that sequence one by one, you would still need to find a way of selecting the proper function of pair conversion from the tuple type: that's basically ad-hoc polymorphism, ie. you would need to be able to overload a function on its parameters' types(1). Unfortunately, OCaml doesn't support that out of the box.
One possibility would be perhaps (I have no experience doing that) to implement an extension which would extract the type information of a given expression, and generate the correct code to process it in your own code.
A flexible technique consists in having that extension generate an algebraic description of the tuples types, and use that description as an equality witness in the code which will process the tuples:
type _ w =
| U : (unit * unit) w
| IF : 'a w -> ((int * float) * 'a) w
| FI : 'a w -> ((float * int) * 'a) w
(* other constructors if necessary *)
(* data *)
let a = 1,1.0
let b = 2.0, 2
let c = 3.0, 3
let d = 4, 4.0
let l = a,(b, (c,(d,((),()))))
(* witness *)
let w = IF (FI (FI (IF U)))
(* the type parameter of w should be the same as l type *)
let rec conv : type a b. (a * b) w -> (a * b) -> num list = fun w (x, xs) ->
match w with
U -> []
| IF w' -> let i,f = x in (Int I)::(Float f)::(conv w' xs)
(* etc *)
Here, we encode the type level nil list as (unit * unit) w.
A coalgebraic approach would require to register function overloads to the conversion function polymorphic signature within the extension, and let it pick the right one from the function overload dictionary.
There's a discussion on that topic on the LtU site.
Thanks to everybody who answered. I finally found a solution, using a bit of magic:
# type num = Int of int | Float of float;;
# let to_num x = if Obj.is_int (Obj.repr x) then
Int (Obj.magic (Obj.repr x) : int)
else
Float ((Obj.magic (Obj.repr x) : float));;
# let pair_to_num (a,b) = [to_num a; to_num b];;
# let myconversion (a,b,c) = [pair_to_num a; pair_to_num b; pair_to_num c];;
and the test:
# myconversion ((1,1.0),(0.4,1),(0,0));;
- : num list list = [[Int 1; Float 1.]; [Float 0.4; Int 1]; [Int 0; Int 0]]
# myconversion ((0,0),(1,1.0),(0.4,1));;
- : num list list = [[Int 0; Int 0]; [Int 1; Float 1.]; [Float 0.4; Int 1]]
Magic, the order does not matter and the type is recorded! I can then follow didier's idea to get rid of the pair of superfluous parentheses.
I am new to OCaml and I am trying to write a function to do this:
(4,a)(1,b)(2,c)(2,a)(1,d)(4,e) --> ((4 a) b (2 c) (2 a) d (4 e))
and this is what I wrote:
let rec transform l =
match l with
| (x,y)::t -> if x = 1 then y::transform(t) else [x; y]::transform(t)
| [] -> []
I put it in the ocaml interpreter but error generated like this:
Error: This expression has type int list
but an expression was expected of type int
Could anyone give some help?
Your example transformation doesn't make it clear what the types of the values are supposed to be.
If they're supposed to be lists, the result isn't a possible list in OCaml. OCaml lists are homogeneous, i.e., all the elements of the list have the same type. This is (in essence) what the compiler is complaining about.
Update
Looking at your code, the problem is here:
if x = 1
then y :: transform (t)
else [x; y] :: transform t
Let's say the type of y is 'a. The expression after then seems to have type 'a list, because y is the head of the list. The expression after else seems to have type 'a list list, because a list containing y is the head of the list. These aren't the same type.
The main problem is to decide how to represent something as either (4 a) or b. The usual OCaml way to represent something-or-something-else is variants, so let's define one of those:
type 'a element =
| Single of 'a
| Count of int * 'a
let rec transform = function
| [] -> []
| (x,y)::t ->
if x = 1 then Single y::transform t
else Count (x, y)::transform t
Note that this won't print in quite the way you want, unless you register a printer with the toplevel.
Or better:
let compact (x, y) =
if x = 1 then Single y else Count (x, y)
let transform list = List.map compact list
I am trying to stick heterogeneous types in a list making use of flexible types
type IFilter<'a> =
abstract member Filter: 'a -> 'a
type Cap<'a when 'a: comparison> (cap) =
interface IFilter<'a> with
member this.Filter x =
if x < cap
then x
else cap
type Floor<'a when 'a: comparison> (floor) =
interface IFilter<'a> with
member this.Filter x =
if x > floor
then x
else floor
type Calculator<'a, 'b when 'b:> IFilter<'a>> (aFilter: 'b, operation: 'a -> 'a) =
member this.Calculate x =
let y = x |> operation
aFilter.Filter y
type TowerControl<'a> () =
let mutable calculationStack = List.empty
member this.addCalculation (x: Calculator<'a, #IFilter<'a>> ) =
let newList = x::calculationStack
calculationStack <- newList
let floor10 = Floor<int> 10
let calc1 = Calculator<int, Floor<int>> (floor10, ((+) 10))
let cap10 = Cap 10
let calc2 = Calculator (cap10, ((-) 5))
let tower = TowerControl<int> ()
tower.addCalculation calc1
tower.addCalculation calc2
In the example above
member this.addCalculation (x: Calculator<'a, #IFiler<'a>> ) =
produces the error
error FS0670: This code is not sufficiently generic. The type variable 'a could not be generalized because it would escape its scope.
Apologies if a similar question has already been posted.
Thank you.
There's no easy way to do this. It looks like you really want calculationStack to have type:
(∃('t:>IFilter<'a>).Calculator<'a, 't>) list
but F# doesn't provide existential types. You can use the "double-negation encoding" ∃'t.f<'t> = ∀'x.(∀'t.f<'t>->'x)->'x to come up with the following workaround:
// helper type representing ∀'t.Calculator<'t>->'x
type AnyCalc<'x,'a> = abstract Apply<'t when 't :> IFilter<'a>> : Calculator<'a,'t> -> 'x
// type representing ∃('t:>IFilter<'a>).Calculator<'a, 't>
type ExCalc<'a> = abstract Apply : AnyCalc<'x,'a> -> 'x
// packs a particular Calculator<'a,'t> into an ExCalc<'a>
let pack f = { new ExCalc<'a> with member this.Apply(i) = i.Apply f }
// all packing and unpacking hidden here
type TowerControl<'a> () =
let mutable calculationStack = List.empty
// note: type inferred correctly!
member this.addCalculation x =
let newList = (pack x)::calculationStack
calculationStack <- newList
// added this to show how to unpack the calculations for application
member this.SequenceCalculations (v:'a) =
calculationStack |> List.fold (fun v i -> i.Apply { new AnyCalc<_,_> with member this.Apply c = c.Calculate v }) v
// the remaining code is untouched
let floor10 = Floor<int> 10
let calc1 = Calculator<int, Floor<int>> (floor10, ((+) 10))
let cap10 = Cap 10
let calc2 = Calculator (cap10, ((-) 5))
let tower = TowerControl<int> ()
tower.addCalculation calc1
tower.addCalculation calc2
This has the big advantage that it works without modifying the Calculator<_,_> type, and that the semantics are exactly what you want, but the following disadvantages:
It's hard to follow if you're unfamiliar with this way of encoding existentials.
Even if you are familiar, there's a lot of ugly boilerplate (the two helper types) since F# doesn't allow anonymous universal qualification either. That is, even given that F# doesn't directly support existential types, it would be much easier to read if you could write something like:
type ExCalc<'a> = ∀'x.(∀('t:>IFilter<'a>).Calculator<'a,'t>->'x)->'x
let pack (c:Calculator<'a,'t>) : ExCalc<'a> = fun f -> f c
type TowerControl<'a>() =
...
member this.SequenceCalcualtions (v:'a) =
calculationStack |> List.fold (fun v i -> i (fun c -> c.Calculate v)) v
But instead we've got to come up with names for both helper types and their single methods. This ends up making the code hard to follow, even for someone already familiar with the general technique.
On the off chance that you own the Calculator<_,_> class, there's a much simpler solution that might work (it may also depend on the signatures of the methods of the real Calcuator<,> class, if it's more complex than what you've presented here): introduce an ICalculator<'a> interface, have Calculator<_,_> implement that, and make calculationStack a list of values of that interface type. This will be much more straightforward and easier for people to understand, but is only possible if you own Calculator<_,_> (or if there's already an existing interface you can piggy back on). You can even make the interface private, so that only your code is aware of its existence. Here's how that would look:
type private ICalculator<'a> = abstract Calculate : 'a -> 'a
type Calculator<'a, 'b when 'b:> IFilter<'a>> (aFilter: 'b, operation: 'a -> 'a) =
member this.Calculate x =
let y = x |> operation
aFilter.Filter y
interface ICalculator<'a> with
member this.Calculate x = this.Calculate x
type TowerControl<'a> () =
let mutable calculationStack = List.empty
member this.addCalculation (x: Calculator<'a, #IFilter<'a>> ) =
let newList = (x :> ICalculator<'a>)::calculationStack
calculationStack <- newList
member this.SequenceCalculations (v:'a) =
calculationStack |> List.fold (fun v c -> c.Calculate v) v
I need to convert a list into a function. I've managed to make the list into a list of tuples. So I have something like this now:
[Expr, (Expr, [[T"("; N Expr; T")"]; [N Num]; [N Expr; N Binop; N Expr]; [N Lvalue]; [N Incrop; N Lvalue]; [N Lvalue; N Incrop]]
Lvalue, [[T"$"; N Expr]])]
I want the final result to look something like:
(Expr,
function
| Expr ->
[[N Term; N Binop; N Expr];
[N Term]]
| Lvalue ->
[[T"$"; N Expr]])
I'm mostly stuck on how I can implement the OR symbols (|). Any advice would be greatly appreciated. Thanks!
You're describing things as if you want to generate the source of your function. That doesn't make a lot of sense unless you're writing some kind of preprocessing tool.
Assuming you're not working on a preprocessor, you should think about what you want the function to do, rather than the textual form it should have. You can easily get the functionality you seem to want--it basically works like the List.assoc function. But you can't do it by creating a certain textual form for the function at runtime.
Here's a function that translates a list of pairs into a lookup function:
# let makeLookup pairs = fun x -> List.assoc x pairs;;
val makeLookup : ('a * 'b) list -> 'a -> 'b = <fun>
# let f = makeLookup [(1, "yes"); (2, "no")];;
val f : int -> string = <fun>
# f 1;;
- : string = "yes"
# f 2;;
- : string = "no"
#
(In fact makeLookup is the same as List.assoc with its parameters reversed.)