dennis@boulder.Colorado.EDU (Dennis Heimbigner) (09/19/90)
I have only recently begun to look at SML and I am curious as to the best method for representing functions that are defined by specifying a set of pairs of values, where the set contents varies over time. This is more-or-less analogous to prolog assert/retract or to functional data base model base functions. For example, I want to associate the set of pairs: (1,2) (17,9) (23,-1) with the function f, such that e.g, f(17) = 9, and so on. Then I want to be able to change this set by replacing some pairs and have the function f reflect these changes. The only way I can see to do this in SML is to associate a variable, f_var, with f such that f_var contains the set of pairs. Modifying the set then consists of reconstructing the set and re-storing it into the variable. Is there some simpler &/or cleaner approach to this? -Dennis Heimbigner (dennis@boulder.colorado.edu)
stabl@unipas.fmi.uni-passau.de (Robert Stabl) (09/20/90)
>>>>> In article <26470@boulder.Colorado.EDU>, dennis@boulder.Colorado.EDU (Dennis Heimbigner) writes: Sorry for the long citation but it is needed for better understanding: Dennis> I have only recently begun to look at SML and I am curious Dennis> as to the best method for representing functions that are Dennis> defined by specifying a set of pairs of values, where the set contents Dennis> varies over time. This is more-or-less analogous to prolog assert/retract Dennis> or to functional data base model base functions. Dennis> For example, I want to associate the set of pairs: Dennis> (1,2) Dennis> (17,9) Dennis> (23,-1) Dennis> with the function f, such that e.g, f(17) = 9, and so on. Dennis> Then I want to be able to change this set by replacing some Dennis> pairs and have the function f reflect these changes. Dennis> The only way I can see to do this in SML is to Dennis> associate a variable, f_var, with f such that f_var Dennis> contains the set of pairs. Modifying the set then Dennis> consists of reconstructing the set and re-storing it into Dennis> the variable. This could be *one* way. But, since SML is a *functional* language, try the following (the input follows the '-', SML output the '>'), the following functions were written using "Standard ML of New Jersey, Version 0.56": - exception unbound; (* needed for undefined values *) > exception unbound - fun update f (x, y) = fn n => if (n = x) then y else f (n); > val update = fn : (''a -> 'b) -> ''a * 'b -> ''a -> 'b (* this function updates f with the new pair (x, y) *) - fun raise_unbound x = raise unbound; > val raise_unbound = fn : 'a -> 'b (* The first update uses this function *) - val f = update raise_unbound (1, 2); > val f = fn : int -> int (* the first pair *) - val f = update f (17, 9); > val f = fn : int -> int (* the next one *) - val f = update f (23, ~1); > val f = fn : int -> int (* and so on *) (* now the application of f *) - f(17); > val it = 9 : int - f(23); > val it = ~1 : int - f(3); > uncaught exception unbound Hope this helps. -- >>>>>>>>>> Robert Stabl <<<>>> stabl@unipas.fmi.uni-passau.de <<<<<<<<<<
norman@d.cs.okstate.edu (Norman Graham) (09/20/90)
From article <STABL.90Sep19204925@trillian-gw.fmi.uni-passau.de>, by stabl@unipas.fmi.uni-passau.de (Robert Stabl): > In article <26470@boulder.Colorado.EDU>, dennis@boulder.Colorado.EDU (Dennis Heimbigner) writes: >> [Omitted discussion where Dennis wants to create a function dynamically, >> by adding (or removing) input/output information to (or from) the >> function at run time.] Dennis originally asked for something analogous to Prolog's database manipulated with assert and retract. Since this is 'state', and purely functional systems are stateless, you obviously can't have it. Variables do not change their values over time; and since a named function is just a variable bound to a 'function value', that variable must represent the same function for the life of the variable. [This is very basic stuff and is provided only for the benefit of novice functional programmers.] [BTW, the charter of this newsgroup forbids discussion of imperative features found in some 'impure' functional languages. So SML references are out for now.] > [Now, Robert provides a SML example that illustrates what he thinks > Dennis wants. I've omitted some SML responses for brevity.] > > - exception unbound; (* needed for undefined values *) > > - fun update f (x, y) = fn n => if (n = x) then y else f (n); > (* this function updates f with the new pair (x, y) *) > > - fun raise_unbound x = raise unbound; > (* The first update uses this function *) > > - val f = update raise_unbound (1, 2); > (* the first pair *) > > - val f = update f (17, 9); > (* the next one *) > > - val f = update f (23, ~1); > (* and so on *) > > (* now the application of f *) > - f(17); >> val it = 9 : int > > - f(23); >> val it = ~1 : int > > - f(3); >> uncaught exception unbound The choice of names in this example may confuse some novice functional programmers. First, the function 'update' really doesn't update anything: It merely creates a new function value that is a little more defined than the function value passed to it. Second, the three 'val f = ...' expressions are not destructively updating f: Each f is a _different_ name--you might as well have called them f1, f2, and f3. The command interpreter creates a new lexical scope for each definition of f. Think of the above example as let f = update raise_unbound (1, 2) in let f = update f (17, 9) in let f = update f (23, ~1) in [f(17),f(23),f(3)] end end end I hope this clarifies things somewhat. Maybe I just misunderstood the question... Cheers, Norm -- Norman Graham <norman@a.cs.okstate.edu> {cbosgd,rutgers}!okstate!norman The opinions expressed herein do not necessarily reflect the views of the state of Oklahoma, Oklahoma State University, OSU's Department of Computer Science, or of the writer himself.
stabl@unipas.fmi.uni-passau.de (Robert Stabl) (09/21/90)
>>>>> In article <1990Sep20.074513.19190@d.cs.okstate.edu>, norman@d.cs.okstate.edu (Norman Graham) writes: [SML functions deleted] Norman> The choice of names in this example may confuse some novice functional Norman> programmers. First, the function 'update' really doesn't update Norman> anything: It merely creates a new function value that is a little more Norman> defined than the function value passed to it. Second, the three Norman> 'val f = ...' expressions are not destructively updating f: Each f Norman> is a _different_ name--you might as well have called them f1, f2, and f3. Norman is right, the function names were misleading (esp. the name f). But, I wanted to show that (higher-order) functional programming can be used to define databases, not implementing them by arrays, lists, or any other standard method. Fur further details I strongly recommend the following report: Stefan Sokolowski: "Applicative High-Order Programming, or Standard ML in the Battlefield", University of Passau, MIP-8908, February 1989. This report contains many, many examples concerning high-order functions, polymorphism, data types, implementation issues (type inference, interpretation, and compilation), structures, functors, signatures, "the art of applicative programming", and so on. The report results from an one-semester course on applicative high-order programming in 1988. -- >>>>>>>>>> Robert Stabl <<<>>> stabl@unipas.fmi.uni-passau.de <<<<<<<<<<
norman@d.cs.okstate.edu (Norman Graham) (09/22/90)
From article <STABL.90Sep20195507@trillian-gw.fmi.uni-passau.de>, by stabl@unipas.fmi.uni-passau.de (Robert Stabl): > But, I wanted to show that (higher-order) functional programming can be used > to define databases, not implementing them by arrays, lists, or any other > standard method. Right. You're example showed an important technique with which all functional programmers should be familiar: A functional (higher-order function) can be used to create a new function that is better defined than the original function. This is the same technique that denotational semanticists use to describe stores and environments. Yours, Norm -- Norman Graham <norman@a.cs.okstate.edu> {cbosgd,rutgers}!okstate!norman The opinions expressed herein do not necessarily reflect the views of the state of Oklahoma, Oklahoma State University, OSU's Department of Computer Science, or of the writer himself.
zmacx07@doc.ic.ac.uk (Simon E Spero) (09/23/90)
In article <STABL.90Sep20195507@trillian-gw.fmi.uni-passau.de> stabl@unipas.fmi.uni-passau.de (Robert Stabl) writes: > >Norman is right, the function names were misleading (esp. the name f). >But, I wanted to show that (higher-order) functional programming can be used >to define databases, not implementing them by arrays, lists, or any other >standard method. > The code in your example strongly resembles the way stores are handled in denotational semantics. Surely the chain of closures that results from this process would take up much more heap space than the standard methods, and be O(N) in time? Surely it would be better to store the data in a more efficent manner (an AVL tree, or suchlike), and to only package it up in function when one is needed ; foo tree <= let f == lambda x => look_up(tree,x) in map (f,[1,2,3] By the way, prehaps the best way of handling this problem is using a hash-table, but this is not really an option unless one is prepared to supply all values in one hit. Ever get the craving for a := ? :-( Simon -- zmacx07@uk.ac.ic.doc | sispero@cix.co.uk | ..!mcsun!ukc!slxsys!cix!sispero ------------------------------------------------------------------------------ The Poll Tax. | Saddam Hussein runs Lotus 123 on | DoC,IC,London SW7 2BZ I'm Not. Are you?| Apple Macs.| I love the smell of Sarin in the morning
dbm@alice.UUCP (David MacQueen) (09/28/90)
Standard ML does have references and assignments, and some implementations (such as Standard ML of New Jersey) have arrays with destructive array update. So it is possible to define hash tables. src/util/intmap.sml in the SML of New Jersey distribution is one such definition. Dave MacQueen macqueen@research.att.com
zmacx07@asunfs.doc.ic.ac.uk (Simon E Spero) (09/29/90)
In article <11396@alice.UUCP> dbm@alice.UUCP (David MacQueen) writes:
Standard ML does have references and assignments, and some implementations
(such as Standard ML of New Jersey) have arrays with destructive array
update. So it is possible to define hash tables. src/util/intmap.sml
in the SML of New Jersey distribution is one such definition.
Yes, but I thought we weren't supposed to talk about those sort of
perversions here, unless they guaranteed Ref. Transparency :-)
Still, this thread, and the parallel discussion in comp.lang.prolog on
declarative arrays, did put me in mind of one idea:
Since workstation screens have got bigger and bigger, with more and more
bit-planes, a lot of work has gone into producing chips which can copy and
move large blocks of contiguous memory very quickly. Has anybody ever tried
applying these BLTers to the problem of declarative arrays? After all,
the main difficulty with most schemes is that whilst they can catch most
cases where the physical array can be reused, most of them
seem to get really complex when applied to examples that weren't in
appendix A of the paper describing them :-)
If you have a fast BLTer behind the stumps, you should be able to use
a simpler algorithm, which combined with compile-time garbage collection
and a clever instruction scheduler, should make it possible to have all
copying performed in parallel with useful work.
Although copying will turn over a lot of memory, the holes in the heap
left will be precisely the right size for further generations of the same
array.
Has anybody tried this approach?
Simon
--
sispero@compulink.cix.co.uk ..!mcsun!ukc!slxsys!cix!sispero
------------------------------------------------------------------------------
The Poll Tax. | Saddam Hussein runs | +44-(0)81-500-3000
I'm Not. Are you?| Lotus 123 on Apple Macs |"Read my lips. No Nuke Tactics"
otto@canon.co.uk (G. Paul Otto) (10/01/90)
In article <11396@alice.UUCP> dbm@alice.UUCP (mh8896) writes: > >Standard ML does have references and assignments, and some implementations >(such as Standard ML of New Jersey) have arrays with destructive array >update. So it is possible to define hash tables. src/util/intmap.sml >in the SML of New Jersey distribution is one such definition. > >Dave MacQueen >macqueen@research.att.com Apologies for my ignorance about ML, but I'm curious: can you define a generic hash function in ML? (i.e. a function which can take a argument of *any* type (on which equality is defined), and map it (in some plausible way) onto a range of integers.) If so, how? Paul ------------------------------------ Paul Otto, Canon Research Centre Europe Ltd., 17-20 Frederick Sanger Rd, Surrey Research Park, Guildford, Surrey, GU2 5YD, UK. NRS: otto@uk.co.canon Internet: otto%canon.co.uk UUCP: otto@canon.uucp PATH: ..!mcsun!ukc!uos-ee!canon!otto Tel: +44 483 574325 Fax: +44 483 574360
der@otter.hpl.hp.com (Dave Reynolds) (10/02/90)
> Apologies for my ignorance about ML, but I'm curious: can you define a > generic hash function in ML? (i.e. a function which can take a argument > of *any* type (on which equality is defined), and map it (in some plausible > way) onto a range of integers.) If so, how? No, there doesn't seem to be any satisfying way of doing this. There is certainly no built in hashing scheme as found in prolog, smalltalk etc. Not least amongst your problems is that there are no generic functions just polymorphic functions, not even user overloading. In pactice this is not so great a problem since you can't have inhomogeneous collections either! This means that for a given hash map you can only insert elements of the same type and only need a monomorphic hash function. In our local library we have a run time description (called a 'typeSpec') for each type we are interested in, which contains (amongst other things) a hash function. When you create an instance of a hash map you bind into the map a 'typeSpec' for the domain of the map. Then all the hash map functions are polymorphic on the domain of the map and rely on the typeSpec supplied as part of the map datastructure to provide little things like the hashing function. This works reasonably well for built in types and a few 'standard' constructed types but it is an annoying overhead to have to define a 'typeSpec' for each user type you might want to use as a map domain. All the hash mapping schemes we have experimented with in ML have suffered from the following limitations: (1) Only homogeneous collections/maps. (2) Inefficient unless you use an exposed imperative implementation. (3) Lack of general hashing function. Whilst (3) is annoying I've typically found it to be the least of my worries. Dave ------------------------------------------------------------------ Dave Reynolds | Phone: (0272) 799910 x 24165 Hewlett-Packard Laboratories | der@hplb.lb.hp.co.uk - UKnet Filton Road, Stoke Gifford | der@hplb.hpl.hp.com - Internet Bristol BS12 6QZ, ENGLAND | Dave Reynolds/HPC600/UX - HPDesk