First code
We have working code.
I have tagged a recent commit to give a snapshot of the code at this point. Given the possibility that some decisions will be revisited and some of this code revised, this snapshot preserves this first cut.
The content
The code here is all F#. Mostly it is ported from the C# ClojureCLR implementation, but with an eye to writing idiomatic F#. Given how it will be used, I had do some things one might avoid in a closed F# implementation. For example, given how nil
(= null
) is used in Clojure, I could not think of how to avoid a liberal sprinkling of the [<AllowNullLiteral>]
attribute on interfaces and classes. Tuple arguments are used often instead of curried functions. Because of overloading, some groups of functions that could have been gathered in a module are in a static (sealed abstract) class. When I understand the code better, I’ll revisit some of this. But I wanted to make some progress now.
For those with some familiarity with the existing Clojure implementations, know that I have restructured the code substantially. There are multiple projects. I have tried to use namespaces appropriately This will have consequences when it comes to doing the Clojure interop that you see in core.clj
and company, but given that these internals are to be accessed by Clojure users through the clojure.core
environment, this should remain
This first snapshot has the following functionality.
-
Clojure.BigArith
– this project (and namespace) provides-
BigDecimal
- implements an immutable, arbitrary precision, signed decimal. This implementation was inspired by the General Decimal Arithmetic Specification. I did not implement the entire specification. For one thing, it is big and hairy. For another, I really only needed to miimic the API ofjava.math.BigDecimal
, as that is all Clojure uses. My implementation is close to the X3.274 subset of the GDAS, meaning I do not implement infinite values, NaNs, subnormal values, and negative zero, along with few other things. I’d have to go read a book to find out what a subnormal value is. Maybe someday.My C# implementation of
BigDecimal
was based on my own implementation of aBigInteger
class. Back in the day, I didn’t find a usableBigInteger
implemenetation, so I just built my own. I based this new implementation ofBigDecimal
onSystem.Numerics.BigInteger
. I didn’t not bother porting myBigInteger
. -
Rational
– Not used in Clojoure. Clojure has its own, rather limited,clojure.lang.Ratio
. Mine is cooler, but no matter; I just wrote this for fun.
-
-
Clojure.Numerics
contains:-
Murmur3
- An implementation of the Murmuer3 hashing API. Clojure on the JVM imported the Guava Murmur3 implementation and made some changes. I copied the API and based the algorithms on the description on Wikipedia. See also SMHasher. Murmur3 provides the mechanics for ourhasheq
implementations. -
Ratio
- see above. This is minor. It doesn’t even implement its own arithmetic, relying onNumbers
for that. -
Converters
- I pulled the code used to convertObject
s to a numeric type (when possible) fromclojure.lang.Util
to this project. Makes more sense here, and I can use it here. This is part of the deconstruction of the massiveUtil
andRT
classes in order to decouple types. -
Numbers
– the big enchilada. Described in the previous posts. Big. I may have a few more unit tests to write. But there are over 400 tests now. I’m feeling pretty good about it. -
Hashing
– I moved the utility code supporting hashing fromUtil
to here.
-
-
Clojure.Collections
– The start of the implementation of all the Clojure collections. In this snapshot:-
The interfaces – you’ve been introduced to
Seqable
,IPersistentCollection
, andISeq
, but they are joined by essentially all the other interfaces that are used (I counted 32 more.) -
AFn
– an abstract base class to help with definingIFn
derivatives. I’ll post about this some other time. I needed it early on to help testIReduce
forIPersistentCollection
. Those tests are not in this snapshot. A post for another day. -
SeqEnumerator
– provides enumerators (= Java iterator) forISeq
’s.ASeq
needs this and it can be implemented without any dependencies, other than on the interfaceISeq
itself. -
The core types to enable us to properly define the many sequential data structures to come:
ASeq
Cons
EmptyList
PersistentList
As described in a previous post, these are mutually dependent.
-
Enough bits and pieces of
RT
andUtil
to get us going. Only a vestigial ipmlementation ofRT.seq
, as discussed. Enough to get started, but I don’t have the extension mechanism defined yet. That will have to be soon, as we will be adding to its repertoire soon. -
LazySeq
–I had a version of it from 18 months ago when I first started playing with this stuff, so I just tossed it in.) Soon we’ll need to have a little chat about laziness, chunking, and reducing.
-
There are test suites written in Expecto for each of the projects. They are executables. You can just run them.
Some random notes on the code text
Naming of functions and methods is a complete shambles, as it is for the C# code for ClojureCLR today. From the beginning of that project I was faced with reconciling the different capitalization standards of Java and C#. I ended up with a mixture. I kept some names with the initial lowercase just so I would have to do less rewriting the Clojure source; other places, I went with intial uppercase. It’s a mess. I regret it.
And this code is a mess, too. And I don’t care. For now. I don’t wan I nt to think about it at this point. I’ll have a big renaming party eventually.
Coming a little to my own defense, the situation in F# is a little confused, too. There are coding guidelines for F# that are pretty clear, at least when the project is F# only. Other rules come into play if you are creating a library for outside consumption, from C# say. Obviously, there are no rules for writinng F# for Clojure interop.
When I’ve written enough code, I’ll have a better sense of the rules I will abide by. In the meantime, just know that I know. Don’t judge.
What’s next
At this point, it should be pretty easy to march through many the sequential data structures that rely on ASeq
. That includes ArraySeq
, ChunkedCons
, Cycle
, EnumeratorSeq
, Iterate
, LongRange
, Range
, Repeat
, and StringSeq
. I may do some of these just take the occasional break from our next big adventure: maps.