minimal changes to C
Ben
Ben <neb@one.net>
Wed, 5 Apr 2000 01:13:18 -0400
--45Z9DzgjV8m4Oswq
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
This reply is long, I probably over did the Haskell stuff.
On Mon, Apr 03, 2000 at 08:21:45PM -0400, Ben wrote:
> You write:
> > On Mon, Apr 03, 2000 at 03:15:34PM -0400, Kragen Sitaker wrote:
> > > It's a shame you didn't post this to kragen-discuss. Would you like =
to?
> >=20
> > Hm, I will forward it to the list later. Should I forward this response=
as
> > well?
>=20
> Sure, send the whole thread if you like.
I did this yesterday but didn't actually acquire the time to reply.
> > > You write:
> > > > On Mon, Apr 03, 2000 at 01:30:57PM -0400, Kragen Sitaker wrote:
> > > > It would probably be easiest to just add a keyword for tail or not-=
tail
> > > > depending upon which is the default behavior. Pizza uses "continue"=
as a
> > > > keyword before the return time of a function to indicate tail recur=
sion.
> > > > Pizza (http://www.cis.unisa.edu.au/~pizza/) has a few of the other =
thin=3D
> > gs
> > > > you mentioned, it is based on Sun's jvm platform though.
> > >=3D20
> > > Thanks for the pointer! I hadn't looked at the Pizza site since July.
> > >=3D20
> > > In a way, C-sane is very similar to Java.
> >=20
> > Well the way you describe the module system it sounds a lot closer to P=
erl's
> > OO system then Java's. Perl can do things like inheritance (AUTOLOAD, a=
nd
> > other tricks) though which would be harder to implement in a language w=
hich
> > is compiled into machine code.
>=20
> I didn't get into OO-ness at all because I don't understand it enough
> to believe in it. :)
I know a few people who don't believe in OO at all. Although the Plan 9
(/Brazil) people describe their operating system as OO, at least in the
FAQ. Which I guess could qualify Unices as OO as well.
> Perl's and Java's package systems are very similar; the major
> difference is that Java is designed to be compiled easily.
I am not familiar enough with other OO systems to differentiate. I would
imagine that Java makes a lot more decisions at compile time then Perl does.
I have looked at smalltalk briefly but couldn't persuade myself to get into
it.
> I meant it's very similar to Java in that it takes features from
> high-level languages and tries to fit them into C (or, in Java's case,
> C++). Some of the features I want (gc, bounds-checking, a package
> system that obviates .h files) are among Java's features.
>=20
> > I am almost done reading a book about Haskell. The typing system is pre=
tty
> > complex in comparison to C's, but it gives you a lot of flexability.
>=20
> Can you give me a nutshell summary? Or should I just buckle down and
> whack at a book for a while? :)
Breath 1, 2, 3... Here we go:
-
A function's type is defined with the following syntax:
func :: Integer -> Integer -> Integer
This function named func takes to arguments which are of the type Integer
and returns an integer. The :: can be read, "has a type of." We could define
func as:
func x y =3D (x * x) + (y * y)
So: func 2 3 evaluates to an Integer, (2*2) + (3*3) =3D> 4 + 9 =3D> 13.
But -> is left associative which is convenient since func 2 :: (Integer ->
Integer). func 2 is a function which takes one argument and adds 4 to it's
square returning an Integer.
So functions are just explicitly grouped with parens in the type definition.
Here is a function which applies its argument its second argument.
foo :: (Integer -> Integer) -> Integer -> Integer
foo f x =3D f x
-
For completeness I'll mention lists and tuples briefly here: lists are
syntactically represented as [] throughout Haskell and tuples as (). Lists
can be of any length (0 \to \infty) but they must be of the same type and
tuples must be of a defined length but can contain any type. I'll give two
quick simple examples and move on.
average :: [Integer] -> Double
The average function might take a list of Integers, sum them and divide them
by the length of the list.
recordGrab :: [(Int, [Char], Double)]
Might search though a list of tuples of length 3 defined by an Int, a list
of Chars, and a Double. This is ugly! (we collectively say) well there is a
way to alias types. If your programming something useful it makes things
more readable.
type Index =3D Int
type Name =3D [Char]
type Baldness =3D Double
type Record =3D (Index, Name, Baldness)
type Database =3D [Record]
This is nice. :).
-
This is all been fun and cute but pretty useless and we can see it quickly
getting annoying, so there is polymorphic typing as well, and as we will see
lots of types of typing.
Our foo above could be generalized to:
foo :: (a -> b) -> a -> b
foo f x =3D f x
Where a and b aren't types we want to explicitly define. Now we can use foo
on a function which uses Double, Float, or Tree if we wanted. Notice though
that there remains an easy to understand type. Here is the type and
definition of foldr from Prelude.hs:
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr f z [] =3D z
foldr f z (x:xs) =3D f x (foldr f z xs)
We see that foldr takes as its arguments first a function which takes as
it's arguments type a and b and returns a type b, then something of type b
and a list of type a. Foldr recursively applys the function to the list
turning a lot of those simple 4 line recursive functions in scheme into a
one liner in Haskell.
-
How do we know about types though? We can't just go performing any old
operation on any old type, right? So there are type classes and instances.
We can define a type class which will tell us when we can Baz on a type as:
class Baz a where
baz :: a -> a -> Bool
Where Baz is the class of functions which will do things related to
bazzing. The function baz defined in Baz takes an arguement that is poly. a
which is Bazzable and returns a truth value based on its bazness or what
not.
A function which does something that requires operations on a Baz can be
explicitly declared:
func :: (Baz a) =3D> a -> b
Normally (as with other types of explicit function type definitions) your
compiler will correctly infer things for you.
We can define an instance of Baz for Bool on baz using instance.
instance Baz Bool where
baz x =3D (x =3D=3D True)
In this context we know the types of x and y and can define baz on them.
Suppose we know that a poly. type a is Baz, this means we can baz a but we
can also baz a list of [a]. We can then say,
instance Baz a =3D> Baz [a] where
baz =3D foldr (&&) True
We are only bazzing lists of objects which are already bazzable though. If
we wanted to baz lists of non-bazzables (which doesnt make much sense) the
instance line would look like:
instance Nonbazzable a =3D> Baz [a] where
=2E..
Don't ask me any questions complex questions about these types of instances
though since (having just picked up the language myself) am still a bit
foggy on them still.
Classes (of type definitions) can be derived from each other. If I wanted to
define a class of functions which are Doublabazzable I can use the previous
definition of the Baz class.
class Baz a =3D> Doublabazzable a where
We can also derive from multiple classes.
class (Baz a, Doub a, La a) =3D> Doublabazzable a where
-
Algebraic datatypes are just types with "symbolic" value. They are declared
with data.
data Name =3D Foo | Bar | Baz | Func
For example would allow us to talk about my unimaginative names thoughout
this email. We could define a function which used them as follows:
foo :: Name -> Name
foo Foo =3D Bar
foo Bar =3D Baz
foo Baz =3D Func
foo Func =3D Foo
We could define the boolean type Bool with data:
data Bool =3D True | False
We can also define "product types" such as:
data Zah =3D Zah String Int
We can use Zah with a function:
bar :: Zah -> Int
bar (Zah string x) =3D 2*x + 1
Which is pretty understandable.. bar (Zah "Kragen Discuss" 3) -> 2*3 + 1 ->
7.
These product types can also be polymorphic, and data can be declared
recursively. So I can easily define a binary tree of a.
data Tree a =3D Nil | Node a (Tree a) (Tree a)
We can find the product of all the poly. a Tree's pretty easily:
sumTree :: (Num a) =3D> Tree a -> Int
sumTree Nil =3D 1
sumTree (Node n left righ) =3D n * sumTree left * sumTree right
The function * is defined as part of the class Num.
Since Tree is essentially a new type and not an alias we must ask for
functions to operate on our new type using the deriving key word. It is
pretty straight forward, Tree above can be redefined as:
data Tree a =3D Nil | Node a (Tree a) (Tree a)
deriving (Num)
We could derive others but then I would have to introduce other classes.
--
If you wish to create a new type without the extra overhead entailed when
using data and without just creating an alias you can use newtype.
newtype Ben =3D String
But we would only do this if we didn't want to use the functions on Ben
which we would use on String (or [Char]).
--
That was a general overview of the Haskell type system. It is hard to go
over the type system without going over a lot of the language. If you have
lots of questions or your terribly puzzled then you should definitely look
into getting a book or reading some of the material at www.haskell.org.
I am also fairly new to the language myself so there may be a few errors
here.
> > I know that Perl will have syntax for types at some point (probably Per=
l 6)
> > which will allow you to declare a scalar something like "integer" when =
you
> > lexically scope it with my. I am not very familiar with Common Lisp,
>=20
> Neither am I!
Everyone I have asked about this language says something akin to "Common
Lisp is icky." It would be nice to understand the Maxima source code.
> > What happens if I proclaim something incorrectly?
>=20
> My knowledge of proclaim comes mostly from "Worse Is Better":
> http://cbl.leeds.ac.uk/nikos/tex2html/examples/good-bad-win/node11.html#S=
ECTION00022100000000000000
Oh, this doesn't sound so good.
> According to
> http://www.xanalys.com/software_tools/reference/HyperSpec/FrontMatter/ind=
ex.html
> --- by far the best reference documentation I've ever seen for any
> language --- it's implementation-dependent. :)
This is nice.
> See specifically
> http://www.xanalys.com/software_tools/reference/HyperSpec/Body/fun_procla=
im.html#proclaim
> http://www.xanalys.com/software_tools/reference/HyperSpec/Body/glo_d.html=
#declaration_specifier
> http://www.xanalys.com/software_tools/reference/HyperSpec/Issues/iss278-w=
riteup.html
> http://www.xanalys.com/software_tools/reference/HyperSpec/Body/mac_declai=
m.html#declaim
> http://www.xanalys.com/software_tools/reference/HyperSpec/Body/sym_declar=
e.html#declare
So proclaim, declaim, and declare are all programmer specified functions
which can be used to let the compiler or lisp environment know what to
expect of given data. proclaim occur at runtime and declaim at compile time.
These seem reasonable for loosely typed higher level languages or at least
ones which keep excess information about data types. I would imagine that
they would speed up and even simplify a language such as Perl which could
then spit out an error instead of simply converting one type to another
based on the context.
> > On a side note: One of the things which attracts me to Haskell is the
> > standard Prelude file which contains definitions for many useful functi=
ons
> > (fold[rl]/iterate/...). I saw that the schemers.org people have passed =
an
> > SFRI which defines a library similar to this for scheme but I haven't
> > actually found a scheme environment yet which has it. Do you know of on=
e?
>=20
> I like to think I'm a Scheme stud, but actually, I'm just a novice. I
> don't even know what an SFRI is :)
You can read about them at:
http://srfi.schemers.org
The latest one includes an implementation of a pattern matching function.
> There is this thing called SLIB, which is available as a package for
> Debian. I don't know how the SLIB integration with the numerous Scheme
> implementations that have Debian packages is, though. (I have rscheme,
> guile, and scm installed as Debian packages, without having put any
> effort into it, plus DrScheme; I think there are at least three or four
> other Scheme implementations that have Debian packages.)
I think that slib is a standard library for dealing with modules, I haven't
looked at it carefully though so I could be wrong.
Is DrScheme good? I tried it (or was it MrEd?) over the Summer and couldn't
get used to typing code in something which was not my editor of choice.
Have you used Stalin? It is a scheme compiler without support for eval and
call/cc which is said to be very fast. I am pretty sure that it still
compiles to C though.
Ben.
--45Z9DzgjV8m4Oswq
Content-Type: application/pgp-signature
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.0 (GNU/Linux)
Comment: For info see http://www.gnupg.org
iD8DBQE46sdFZf8gRlnNZgwRASqKAJ9jTzyqwKHchHe7FJGdDGjnLybzlwCaAqEu
ki5/SV6DvgySqna5YyF/1Sg=
=x2oQ
-----END PGP SIGNATURE-----
--45Z9DzgjV8m4Oswq--