Re: topdelcs / decls

1998-10-24 Thread Koen Claessen

On Fri, 23 Oct 1998, Ralf Hinze wrote:

 | If local instance declarations were admissable I could possibly write
 | ... lots of hand-waving ...
 | 
 |  sortBy (rel :: Rel a)  =  sort where instance Ord a where (=) = rel

Look at Mondrian:

  http://www.cs.chalmers.se/~koen/Papers/mondrian.ps

The intention there was that this would be easy to do. Dictonaries are
implemented by records (possibly containing polymorphic functions):

  class Ord a where
  { (=) :: a - a - Bool
  }

defines a record type containing one field: =.

If we want to compare two elements, we can explicitly choose a Ord-record:

  intOrd :: Ord Int
  intOrd = Ord{ (=) = primIntCompare }

  1 intOrd.= 2 :: Bool

Or we can leave it implicit:

  1 = 2 :: Ord Int = Bool

Note that the type expresses that we haven't specified an ordering yet.

Implementing a sorting function, is like adding an extra selector function
to the Ord record. It goes like this:

  sort :: Ord a = [a] - [a]
  sort xs = ... = ... xs ...

Now, if we want to use sort on different orderings:

  sort [1,2,3,4]  :: Ord Int = [Int]
  intOrd.sort [1,2,3,4]   :: [Int]
  crazyOrd.sort [1,2,3,4] :: [Int]
  ...

We can also implement a function that flips a sorting:

  rev :: Ord a - Ord a
  rev ord = Ord{ (=) = flip (ord.=) }

Note that this is defined as a record transformer, rather than as a new
selector function for Ord. And now we can define "revsort", using the
flipped ordering:

  revsort :: Ord a = [a] - [a]
  ord.revsort = (rev ord).sort

I really like these ideas, and the paper has a few more examples.
Unfortunately there seem to be some semantic issues wrong with it (what to
do if you have multiple record in your contexts).

Regards,
Koen.

--
Koen Claessen,
[EMAIL PROTECTED],
http://www.cs.chalmers.se/~koen,
Chalmers University of Technology.





Re: topdelcs / decls

1998-10-24 Thread Felix Schroeter

Hello!

On Fri, Oct 23, 1998 at 01:44:58PM +0200, Johannes Waldmann wrote:
  Your thought would destroy equational reasoning! For example you
  would be able to define different equalties on the same data
  structure. So Red==Black could be False in one place and True 
  in another place. Does that make any sense? 

 well, yes and no, of course :-) 

 for instance, i could want to sort a list,
 according to two different criteria,
 using two different instances of Ord.

newtype IntFunnilyOrdered = IFO Int
instance Ord IntFunnilyOrdered where
  compare (IFO x) (IFO y) | even x  even y = compare x y
  | even x  odd y  = LT
  | odd x  even y  = GT
  | otherwise= compare x y
int_from_ifo (IFO x) = x

newtype IntReverse = IR Int
instance Ord IntReverse where
  compare (IR x) (IR y) = compare y x
int_from_ir (IR x) = x

Now, you can do
  map int_from_ir $ sort $ map IR l
or
  map int_from_ifo $ sort $ map IFO l

Ideally, the compiler should figure out that map IFO and map
int_from_ifo are essentially noops, except changing the class
instances to use.

Or use a function sortWith :: (a - a - Ordering) - [a] - [a]
and give it the ordering to use as parameter.

 moreover, i would need these instances only while sorting,
 so i would like to keep them local.

If you use the instances once, I think using something like sortWith
instead will be more elegant.

 [...]

 i fear there are more problems hidden. let's take this:

 data T = ...

 xx = let instance Ord T where ...
x :: T = ...
  in  x

 yy = let instance Ord T where ...
   y :: T = ...
  in y

 do xx and yy have the same type? yes and no, again,
 it looks like they belong to different (incomparable) subtypes of T.

 what about the expression (xx  yy)? which instance to use?
 none - on the outside it's not visible that T is any Ord instance, 
 so you cannot compare them at all.

Hmmm. So in your sorting example:

sort :: Ord a = [a] - [a]
sort ... = ...  ...,

foo = let instance Ord T where compare ... = ... in sort (something::[T])

There's no Ord instance visible in the definition of sort.

And if you dynamically assign those instances and transport them to
sort, this becomes a real mind twist:

sort :: ... (as above)

somelist :: [T]
somelist = let instance Ord T where ... in (generate some list of values in T)

sortedlist :: [T]
sortedlist = let instance Ord T where [different from the above instance] in
  sort somelist

Now, which instance to usw? That bound to the values when they were
generated, i.e. that local to somelist? Or is that instance replaced by
that in sortedlist by that let instance binding?

That somehow twists my mind :-)

Regards, Felix.





Re: Fixing imports for and namespaces (was: Simon's H98 Notes)

1998-10-24 Thread David Barton

Fergus Henderson writes:

   No, different uids don't work fine in the multiprogrammer case.
   The programmer that is compiling the source code needs read access
   to all of it (for using tools like `grep', if nothing else).  Once
   he has that read access, nothing prevents him from violating the
   encapsulation.

Let's see here --- you want him to be able to do reads like grep but
not refer to the units directly?  You ask too much of *any* mechanism
(unless you restrict operations like grep and others, doing special
versions, in which case they can do the appropriate superuser stuff).
Either you can trust the programmer to follow conventions, or you
restrict any kind of read access; without that restriction, he or shee
can always make a local copy and do what he or she wills.

But even *if* you decide that some more sophisticated mechanism of
version control is necessary, it is properly an operating system
function, *not* a language function.  If you decide that a "grep" is
OK, but compile access is not, there is no reason whatever to decide
that compilation is your only "forbidden" function.  It makes a lot
more sense to add an operating system function --- say, granting
access by tool rather than by specific user or group ID --- that gets
you the finer grained access control you need.  Then you only
implement it once.  Under your suggestion, it not only gets
implemented by multiple tools, but it gets codified in the entry
format (whether a computer language or a document control system) of
multiple tools, each in a different way.  Chaos!

It all boils down to: access control to files is the responsibility of
the operating system, *not* a programming language.  The most a
language should do is make responsible conventions possible and
expressible, and Haskell can do that with a very limited extension.

2) The compiler can (and should) be intelligent enough to detect
   the importation of symbols only through non-functional
   (gather) modules.  This is not a big test to perform.

   So the compiler should enforce this convention?

No; detect it and take advantage of it.

Most of the below is variations on a theme, which make lots of sense
if you accept the basic assumption that enforcing access control
conventions is properly a function of the language feature; under that
assumption, I agree with most of it.  So:

snip

   I don't see how that helps.  Every programmer on the team may need
   to modify any file (in order to fix a bug, for example).  So all
   programmers need write access to every file.

This does not correspond to any configuration controlled project that
I have ever worked on, so I am at sea.  In my world, if you need a
file that is outside your own package, you need to go to the
configuration manager (who may or may not be the project manager) for
permission to check out the file to make the change.  This may be as
simple as an Email, or it may even require review.  Allowing the
programmer to just do it, on his own hook, is well outside any kind of
configuration control guidelines I have ever worked under.

This may be a commercial / university kind of thing.  I know of no
company that would work with these kinds of guidelines, which may
account for our different approach to this whole question.

   Well, normally I check out all the modules in the system.  With
   CVS, I type out `cvs checkout mercury' and it checks out all the
   modules in the entire system, giving me both read and write access
   to all of them.  Then I type `make' and it compiles everything.
   This is nice and simple, and it works.

We work in very different environments!

   Yes, you may be right.  But I don't think a language should require
   the use of a particular configuration management style.  And
   therefore I'm not keen on any solution which relies on the
   configuration management style rather than the language to enforce
   encapsulation.

And, again IMHO, it is the task of the language to *define* the
encapsuation (or to allow that encapsulation to be defined), and the
job of the operating system or programming environment to enforce it
(or to trust to convention, depending).  And still IMHO, Haskell can
do this definition with very little change.

Dave Barton *
[EMAIL PROTECTED] )0(
http://www.averstar.com/~dlb





Re: Functional DSP

1998-10-24 Thread Matthew Donadio

Philip Wadler wrote:
 By the way, FFTW although written in C, was generated by a functional
 program written in Caml.  You can find more details on the web page

I asked the authors (Steven Johnson and Matteo Frigo from MIT) a few
months ago why they chose Objective Caml over SML, Haskell, and Scheme. 
The answer was bascially because they knew it already and it ran well on
one of their older laptops.

I think what it more interesting is that fact that the code uses
explicit recursion (as oppose to "traditional" loop based algorithms)
and all of the codelets/butterflys are executed via byte code.  On top
of that, it managed to beat most other FFT packages available today.

--Matt Donadio ([EMAIL PROTECTED])





Re: Functional DSP

1998-10-24 Thread Jan Skibinski



On Sat, 24 Oct 1998, Philip Wadler wrote:

   I was planning to try similar things you have mentioned
   on your page, such as interfacing to "the fastest FFT in
   the West" (FFTW) via GreenCard, ...
 
 By the way, FFTW although written in C, was generated by a functional
 program written in Caml.  You can find more details on the web page
 
   Functional Programming in the Real World
   http://www.cs.bell-labs.com/~wadler/realword/
 

Yes, I know it, but thank you for pointing it out.

It is amazing to see how useful caml/ocaml is in development
of other goodies, such as Pict, Joint Calculus, Ensemble, etc.
I think that they did a good job with interfacing
it to C in a variety of ways: toplevel, bytecode, native
code, embedded bytecode, etc.; and that's probably one of the
answers why it is so popular - at least among researchers.
 
Jan

 -- P
 





Re: Haskell 98

1998-10-24 Thread Simon Marlow

Simon Peyton-Jones [EMAIL PROTECTED] writes:

 Consider the function
 
   t :: T a = T a - T a
 
 I think that it's far from clear what each of the T's mean!
 Worse, in Haskell 2 we'll also have
 
   t :: T T = T a - T a
 
 In (T T) one is class and the other is a type constructor.

I'm not convinced by the argument "this allows you to write obfuscated
Haskell".  After all, Haskell is already a wonderful language for
writing obfuscated code; eg. what does the following definition mean

f f = f

is it a static error (re-use of 'f'), a type error, or a definition of
the identity function?  (it's the latter).

Here's to cleaning up the language, and to more exciting obfuscated
Haskell competitions!

Cheers,
Simon

-- 
Simon Marlow [EMAIL PROTECTED]
University of Glasgow   http://www.dcs.gla.ac.uk/~simonm/
finger for PGP public key





Re: Functional DSP

1998-10-24 Thread Philip Wadler

I was planning to try similar things you have mentioned
on your page, such as interfacing to "the fastest FFT in
the West" (FFTW) via GreenCard, ...

By the way, FFTW although written in C, was generated by a functional
program written in Caml.  You can find more details on the web page

Functional Programming in the Real World
http://www.cs.bell-labs.com/~wadler/realword/

-- P