Version française
Home     About     Download     Resources     Contact us    
Browse thread
Labels and operators
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: John Prevost <prevost@m...>
Subject: Labels and operators
A friend of mine recently said "if ML had regexp stuff that was as
convenient as Perl, I'd switch to it for everything", and mentioned =~
as something he specifically wanted.  So, as I was walking home
tonight, I thought "hey, I bet I could make some little operators for
the PCRE library and show him!"

But, it also occurred to me that you want to use the nice labelled
optional argument stuff, and I wasn't sure you could do that with
operators.  Here's what I've discovered.

The following definition is kind of non-sensical, since obviously you
need at least one and probably at least two arguments for an infix
operator:

# let (+) ?(x = 1) ?(y = 1) () = x + y;;
val ( + ) : ?x:int -> ?y:int -> unit -> int = <fun>

but, well, it accepts it.  Now, let's see if we can apply this
operator as a function.

# (+) ();;
- : int = 2
# (+) ~x:5 ();;
- : int = 6
# (+) ~x:5 ~y:5 ();;
- : int = 10

Okay, that's as expected.  What about as an operator?  Well, the first
case is obviously degenerate, since we're not giving enough arguments
for a two argument operator.  What about the second and third:

# ~x:5 + ();;
  ---
Syntax error
# ~x:5 + ~y:5 ();;
  ---
Syntax error

Well, that's a little disappointing.  I sort of half expected it,
though, since this isn't function application we're dealing with.

Here's what I was *trying* to do:

# let (=~) s ?iflags ?flags ?rex ?pos pat =
    pmatch ?iflags ?flags ?rex ~pat ?pos s;;
val ( =~ ) :
  string -> ?iflags:Pcre.irflag -> ?flags:Pcre.rflag list ->
    ?rex:Pcre.regexp -> ?pos:int -> string -> bool = <fun>
# "foo" =~ "\s+";;
- : bool false
# "foo" =~ "f";;
- : bool true
# "foo" =~ "f" ~pos:1;;
           ---
This expression is not a function, it cannot be applied
# ("foo" =~ "f") ~pos:1;;
  --------------
This expression is not a function, it cannot be applied
# (=~) "foo" ~pos:1 "f";;
- : bool false
# (=~) "foo" "f" ~pos:1;;
- : bool false

The only solution I can think of is something like:

# let re ?iflags ?flags ?rex ?pos pat = (iflags, flags, rex, Some pat, pos)
val re :
  ?iflags:'a -> ?flags:'b -> ?rex:'c -> ?pos:'d -> 'e ->
    'a option * 'b option * 'c option * 'e option * 'd option =
  <fun>
# let (=~) s (iflags,flags,rex,pat,pos) =
                   pmatch ?iflags ?flags ?rex ?pat ?pos;;
val ( =~ ) :
  string ->
  Pcre.irflag option * Pcre.rflag list option * Pcre.regexp option *
  string option * int option -> bool = <fun>
# "foo" =~ re "f";;
- : bool = true
# "foo" =~ re "f" ~pos:1;;
- : bool = false

Which, well, works, but seems kind of nasty.


Since the syntax of labeled arguments is based around function
application, and since function application (juxtaposition) has higher
precedence than any other "operator", I can see why it's not
syntactically valid to try to use labels on arguments to an operator.
I don't see any clean way of "fixing" this, so I figured I ought to
warn people that while you can define an operator with labeled
arguments, you're not going to get much use of it as an infix.

Well, okay, I think it might be reasonable to change the syntax to
allow this syntax:

<expr1> <op> <labelled args> <expr2>

since the labelled args could not in any way shape or form be thought
to go with either expr1 or expr2.  This would lead to things like:

# "foo" =~ ~pos:1 "f";;
- : bool = false

being possible.  Don't know whether it's a great idea, though.



John.