|
List Info
Thread: "ocaml_beginners"::[] Multiple constructors..
|
|
| "ocaml_beginners"::[] Multiple
constructors.. |
  United States |
2007-10-06 10:33:24 |
|
I'm diving into OCaml by doing a couple of ports. One of the things
that I'm porting has a class with multiple constructors. Is there a
nice way to map that to OCaml? Is there anything like 'case classes'?
Note, the argument lists for the contructors are somewhat disjoint.
Default arguments wouldn't be a good solution.
Thanks,
Michael
__._,_.___
.
__,_._,___
|
| Re: "ocaml_beginners"::[]
Multiple constructors.. |
  United Kingdom |
2007-10-06 10:45:14 |
|
On Saturday 06 October 2007 16:33:24 Michael Feathers wrote:
> I'm diving into OCaml by doing a couple of ports. One of the things
> that I'm porting has a class with multiple constructors. Is there a
> nice way to map that to OCaml? Is there anything like 'case classes'?
> Note, the argument lists for the contructors are somewhat disjoint.
> Default arguments wouldn't be a good solution.
Overloading grates against type inference, so the idiomatic OCaml solution is
to simply write different functions:
let make x y = {Complex.re=x; im=y}
let make_polar t r = make (r*cos t) (r*sin t)
and so on.
--
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/products/?e
__._,_.___
.
__,_._,___
|
| Re: "ocaml_beginners"::[]
Multiple constructors.. |
  United States |
2007-10-06 11:06:45 |
|
Jon Harrop wrote:
>On Saturday 06 October 2007 16:33:24 Michael Feathers wrote:
>
>
>>I'm diving into OCaml by doing a couple of ports. One of the things
>>that I'm porting has a class with multiple constructors. Is there a
>>nice way to map that to OCaml? Is there anything like 'case classes'?
>>Note, the argument lists for the contructors are somewhat disjoint.
>>Default arguments wouldn't be a good solution.
>>
>>
>
>Overloading grates against type inference, so the idiomatic OCaml solution is
>to simply write different functions:
>
> let make x y = {Complex.re=x; im=y}
> let make_polar t r = make (r*cos t) (r*sin t)
>
>and so on.
>
>
>
Thanks. I thought of that.. but the sticking point is that I'm creating
objects so I'd have to create some functions which delegate their
arguments to the object's construction. Doesn't buy much unless I pull the
construction work into the functions. At that point, I'd probably have
a whopper of a class argument list. Well, if there's nothing special
to try as an alternative, I'll try that.
Michael
__._,_.___
.
__,_._,___
|
| Re: "ocaml_beginners"::[]
Multiple constructors.. |
  United Kingdom |
2007-10-06 11:30:26 |
|
On Saturday 06 October 2007 17:06:45 Michael Feathers wrote:
> Thanks. I thought of that.. but the sticking point is that I'm creating
> objects so I'd have to create some functions which delegate their
> arguments to the object's construction. Doesn't buy much unless I pull the
> construction work into the functions. At that point, I'd probably have
> a whopper of a class argument list. Well, if there's nothing special
> to try as an alternative, I'll try that.
I don't follow. The code shouldn't be any longer in OCaml. Can you post code
examples?
For example:
# type complex = < im : float; re : float >;;
type complex = < im : float; re : float >
# let make x y : complex = object method re=x method im=y end;;
val make : float -> float -> complex = <fun>
# let make_polar t r : complex =
object method re=r*.cos t method im=r*.sin t end;;
val make_polar : float -> float -> complex = <fun>
--
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/products/?e
__._,_.___
|
| Re: "ocaml_beginners"::[]
Multiple constructors.. |
  United States |
2007-10-06 11:54:29 |
|
Jon Harrop wrote:
>On Saturday 06 October 2007 17:06:45 Michael Feathers wrote:
>
>
>>Thanks. I thought of that.. but the sticking point is that I'm creating
>>objects so I'd have to create some functions which delegate their
>>arguments to the object's construction. Doesn't buy much unless I pull the
>>construction work into the functions. At that point, I'd probably have
>>a whopper of a class argument list. Well, if there's nothing special
>>to try as an alternative, I'll try that.
>>
>>
>
>I don't follow. The code shouldn't be any longer in OCaml. Can you post code
>examples?
>
>
Sure. I'm porting Ward Cunningham's FIT testing framework. It's very
OO and I'm trying to keep the port close to that until I get more
experience and see better functional ways..
There is a class in FIT called Parse and it has some snake-y construction:
public Parse (String tag, String body, Parse parts, Parse more) {
this.leader = "n";
this.tag = "<"+tag+">";
this.body = body;
this.end = "</"+;tag+">";
this.trailer = "";
this.parts = parts;
this.more = more;
}
static String tags[] = {"table", "tr", "td"};
public Parse (String text) throws ParseException {
this (text, tags, 0, 0);
}
public Parse (String text, String tags[]) throws ParseException {
this (text, tags, 0, 0);
}
public Parse (String text, String tags[], int level, int offset)
throws ParseException {
String lc = text.toLowerCase();
int startTag = lc.indexOf("<"+;tags[level]);
int endTag = lc.indexOf(">", startTag) + 1;
int startEnd = lc.indexOf("</"3;tags[level], endTag);
int endEnd = lc.indexOf(">", startEnd) + 1;
int startMore = lc.indexOf("<"+;tags[level], endEnd);
if (startTag<0 || endTag<0 || startEnd<0 || endEnd<0) {
throw new ParseException ("Can't find tag: "+;tags[level],
offset);
}
leader = text.substring(0,startTag);
tag = text.substring(startTag, endTag);
body = text.substring(endTag, startEnd);
end = text.substring(startEnd,endEnd);
trailer = text.substring(endEnd);
if (level+;1 < tags.length) {
parts = new Parse (body, tags, level+1, offset+;endTag);
body = null;
}
if (startMore>=0) {
more = new Parse (trailer, tags, level, offset+;endEnd);
trailer = null;
}
}
Aside from this construction (which recursively builds a tree of
parses), the parse class itself doesn't have much in the way of
behavior. At this point, I suspect that it's best to pull all of this
parsing into a set of recursive functions and make the class itself more
of a data structure. It would, however, probably have about seven
arguments.. leader, tag, body, end, trailer, parts and more.
I wonder... maybe I can create functions that create 'immediate
objects'. They can use values from the enclosing scope. I could avoid
a lot of parameter passing. I wonder whether immediate objects can
inherit from classes, however.
Michael
__._,_.___
|
| Re: "ocaml_beginners"::[]
Multiple constructors.. |
  United States |
2007-10-08 10:16:57 |
|
On Sat, 06 Oct 2007 12:54:29 -0400, Michael Feathers wrote
> Sure. I'm porting Ward Cunningham's FIT testing framework. It's
> very OO and I'm trying to keep the port close to that until I get
> more experience and see better functional ways..
>
> There is a class in FIT called Parse and it has some snake-y construction:
Well, you may be able to do something like the following which is admitttely
ugly, somewhat poorly written (an off the top of the head translation), and
may not actually work (but it does typecheck):
class type parse_type =
object
val leader : string
val tag : string
val body : string
val ending : string
val trailer : string
val parts : parse_type option
val more : parse_type option
end
;;
exception ParseException of string;;
class parse ?(tags=["table"; "tr"; "td"])
?(text) ?(body)
?(level=0) ?(offset=0)
?(parts) ?(more) ()
: parse_type =
let leader,tag,body,ending,trailer,parts,more =
match tags, text, body with
| [tag], None, Some body ->
"n", "<"^ tag ^ ">", body, "</" ^ tag ^ ">", "", parts, more
| _::_, Some text, None ->
let txt = String.lowercase text in
let tag = List.nth tags level in
let open_tag = Str.regexp_string ("<" ^ tag)
and close_tag = Str.regexp_string ("</" ^ tag) in
begin try
let startTag = Str.search_forward open_tag txt 0 in
let endTag = String.index_from txt startTag '>' + 1 in
let startEnd = Str.search_forward close_tag txt endTag in
let endEnd = String.index_from txt startEnd '>' + 1 in
let startMore =
try Some (Str.search_forward open_tag txt endEnd)
with Not_found -> None
in
let body = String.sub text endTag (startEnd-endTag)
and trailer = String.sub text endEnd (String.length text - endEnd)
in
String.sub text 0 startTag,
String.sub text startTag (endTag-startTag),
body,
String.sub text startEnd (endEnd-startEnd),
trailer,
(if level + 1 < (List.length tags) then
Some (new parse ~text:body
~tags:tags
~level:(level+1)
~offset:(offset+endTag) ()
)
else
None),
(match startMore with
| Some pos -> Some (new parse ~text:trailer
~tags:tags
~level:level
~offset:(offset+endEnd) ()
)
| _ -> None)
with Not_found -> raise (ParseException ("Can't find tag: " ^ tag))
end
| _ -> raise (ParseException "Bad arguments to constructor")
in
object
val leader = leader
val tag = tag
val body = body
val ending = ending
val trailer = trailer
val parts = parts
val more = more
end
;;
- class type parse_type =
object
val body : string
val ending : string
val leader : string
val more : parse_type option
val parts : parse_type option
val tag : string
val trailer : string
end
exception ParseException of string
class parse :
?tags:string list ->
?text:string ->
?body:string ->
?level:int ->
?offset:int -> ?parts:parse_type -> ?more:parse_type -> unit -> parse_type
Basically, all we're doing here is using pattern matching to distingush how
the call is overloaded and we use that to create the values that will
populate the instance variables of our object (which at the moment has no
methods, but that's not too big of a deal).
> Aside from this construction (which recursively builds a tree of
> parses), the parse class itself doesn't have much in the way of
> behavior. At this point, I suspect that it's best to pull all of
> this parsing into a set of recursive functions and make the class
> itself more of a data structure. It would, however, probably have
> about seven arguments.. leader, tag, body, end, trailer, parts and
> more.
Yeah, but as above, mose of those are hidden via optional arguments. The
only issue is that you need to slap a non-labeled argument at the end (here
something of type unit) so that everything plays nice -- see section 4.1 of
the manual for more info.
--
William D. Neumann
__._,_.___
.
__,_._,___
|
| Re: "ocaml_beginners"::[]
Multiple constructors.. |
  United States |
2007-10-08 13:23:37 |
|
William,
Thanks very much. I'll look into that.
Michael
William D. Neumann wrote:
>On Sat, 06 Oct 2007 12:54:29 -0400, Michael Feathers wrote
>
>
>
>>Sure. I'm porting Ward Cunningham's FIT testing framework. It's
>>very OO and I'm trying to keep the port close to that until I get
>>more experience and see better functional ways..
>>
>>There is a class in FIT called Parse and it has some snake-y construction:
>>
>>
>
>Well, you may be able to do something like the following which is admitttely
>ugly, somewhat poorly written (an off the top of the head translation), and
>may not actually work (but it does typecheck):
>
>class type parse_type =
> object
> val leader : string
> val tag : string
> val body : string
> val ending : string
> val trailer : string
> val parts : parse_type option
> val more : parse_type option
> end
>;;
>
>exception ParseException of string;;
>
>class parse ?(tags=["table"; "tr"; "td"])
> ?(text) ?(body)
> ?(level=0) ?(offset=0)
> ?(parts) ?(more) ()
> : parse_type =
> let leader,tag,body,ending,trailer,parts,more =
> match tags, text, body with
> | [tag], None, Some body ->
> "n", "<"^ tag ^ ">", body, "</" ^ tag ^ ">", "", parts, more
>
> | _::_, Some text, None ->
> let txt = String.lowercase text in
> let tag = List.nth tags level in
> let open_tag = Str.regexp_string ("<" ^ tag)
> and close_tag = Str.regexp_string ("</" ^ tag) in
> begin try
> let startTag = Str.search_forward open_tag txt 0 in
> let endTag = String.index_from txt startTag '>' + 1 in
> let startEnd = Str.search_forward close_tag txt endTag in
> let endEnd = String.index_from txt startEnd '>' + 1 in
> let startMore =
> try Some (Str.search_forward open_tag txt endEnd)
> with Not_found -> None
> in
> let body = String.sub text endTag (startEnd-endTag)
> and trailer = String.sub text endEnd (String.length text - endEnd)
> in
> String.sub text 0 startTag,
> String.sub text startTag (endTag-startTag),
> body,
> String.sub text startEnd (endEnd-startEnd),
> trailer,
> (if level + 1 < (List.length tags) then
> Some (new parse ~text:body
> ~tags:tags
> ~level:(level+1)
> ~offset:(offset+endTag) ()
> )
> else
> None),
> (match startMore with
> | Some pos -> Some (new parse ~text:trailer
> ~tags:tags
> ~level:level
> ~offset:(offset+endEnd) ()
> )
> | _ -> None)
> with Not_found -> raise (ParseException ("Can't find tag: " ^ tag))
> end
> | _ -> raise (ParseException "Bad arguments to constructor")
> in
> object
> val leader = leader
> val tag = tag
> val body = body
> val ending = ending
> val trailer = trailer
> val parts = parts
> val more = more
> end
>;;
>
>- class type parse_type =
> object
> val body : string
> val ending : string
> val leader : string
> val more : parse_type option
> val parts : parse_type option
> val tag : string
> val trailer : string
> end
>
>exception ParseException of string
>
>class parse :
> ?tags:string list ->
> ?text:string ->
> ?body:string ->
> ?level:int ->
> ?offset:int -> ?parts:parse_type -> ?more:parse_type -> unit -> parse_type
>
>Basically, all we're doing here is using pattern matching to distingush how
>the call is overloaded and we use that to create the values that will
>populate the instance variables of our object (which at the moment has no
>methods, but that's not too big of a deal).
>
>
>
>>Aside from this construction (which recursively builds a tree of
>>parses), the parse class itself doesn't have much in the way of
>>behavior. At this point, I suspect that it's best to pull all of
>>this parsing into a set of recursive functions and make the class
>>itself more of a data structure. It would, however, probably have
>>about seven arguments.. leader, tag, body, end, trailer, parts and
>>more.
>>
>>
>
>Yeah, but as above, mose of those are hidden via optional arguments. The
>only issue is that you need to slap a non-labeled argument at the end (here
>something of type unit) so that everything plays nice -- see section 4.1 of
>the manual for more info.
>
>--
>
>William D. Neumann
>
>
>
>
__._,_.___
.
__,_._,___
|
[1-7]
|
|