Re: How to use modules in place of Type Classes
Vesa Karvonen <vesa.karvonen-bbCR+/[email protected]>
| Newsgroups | gmane.comp.lang.sml.smlnj |
|---|---|
| Message-ID | <[email protected]> |
Quoting David Eger <eger-oTNwCEtKUwI/[email protected]>: > I'm writing a library to do command line parsing in SML much like > the C getopt() function. Did you notice the GetOpt library that is part of the SML/NJ library (look at the util directory)? > I take a dictionary of expected arguments and their types and a command > line string. I return a dictionary of parsed arguments. > > I don't really care what sort of dictionary I'm passed. Does it have to be a dictionary? An alternative might be to return a list of the arguments and let the caller create a dictionary from the list if desired. Another alternative might be to treat argument parsing as a fold. Your getopt function would then have a type roughly of the form: ... -> ('argument * 'result -> 'result) -> 'result -> ... If the user really wants to build a dictionary, then the result type would be a dictionary type and the function would be the insert operation of the dictionary type. > In order for me to make a generalized GETOPT that accepts any sort of > dictionary, it seems that I have to write my module as a functor, taking > a structure argument and that each of my callers has to explicitly > evaluate the functor. This means that the implementation information > about the underlying representation of a particular dictionary needs to > be threaded through any code base that uses my library all the way down > to the invocation of getopt(). If you decide to functorize your getopt implementation, then I would assume that you would most likely instantiate that functor just once in a given program. This would look roughly like: structure Dict = ... structure GetOpt = MkGetOpt (Dict) The rest of your program would directly refer to the Dict and GetOpt bindings. If you later want to change the dictionary implementation, you would simply change the line that binds Dict. > This seems to add a lot of programmer overhead. That would be the case with library modules (modules that aren't specific to any single application) that wish to access the options. Modules that are specific to a program can refer to the dictionary module directly. > Is there a better way? Depends. I think that the getopt interface (or anything similar to it) is rather low level. Explicitly passing a dictionary of arguments around also sounds like a chore and type-unsafe. In many cases (not all) a process only gets/has a single global set of command line arguments. For such cases I would rather build a library that allows one to concisely implement a "Control" module that specifies the control flags (options) that the program uses. For example, a program implementing the (*nix) rm command would have a Control module with a signature roughly of the following form: signature CONTROL = sig type 'a t (* Type of control flags, you would also provide at least a get -operation for reading control flags. *) val directory : bool t val force : bool t val interactive : bool t val preserveRoot : bool t val recursive : bool t val verbose : bool t val files : string list t (* ... *) end The rest of the program would then refer to the bindings in the Control module. The benefit is that the options are now specified clearly in the signature of the Control module and that your program code can not accidentally refer to non-existent options or refer to an option by an incorrect type. BTW, this is roughly how the MLton compiler handles command line arguments. Also, try entering structure Foo = struct open Control end in SML/NJ. This approach can also be made to work in a multithreaded applications where the control flags may be changed dynamically. In such a case you would use thread local variables for the control flags. Library modules that wish to refer directly to the control flags could be functorized and instantiated with the Control module. Alternatively, such library modules could implement their own control modules that could be initialized by the main program (or they might just parse subsets of the command line by themselves). This way you could avoid functorizing the library modules. > Is there any equivalence to the type class sugar of Haskell that I could use? No. Well, not in the way that you probably think about. Type classes can be thought of as implicit "dictionary" (a record of values) passing. In SML you would pass the dictionary explicitly. > In practice, do SML users just accept a very specific dictionary and have > the caller do the manual conversions? Do they functorize everything? I think that SML users come in all shapes and sizes. Some might just use a specific dictionary implementation. Some might functorize (almost) everything. Some wouldn't use a dictionary at all. -Vesa Karvonen ------------------------------------------------------------------------- Take Surveys. Earn Cash. Influence the Future of IT Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV