So. SML lets you redefine basic operators on basic types

For instance, I could do this-

fun op-(x,y) = x+y

This makes the ‘-’ operator do integer addition.  Reals?  Hah, no subtracting them now!  Fails type checking on anything but ints.

I can also do:

fun op-(x) = ~x;

Now, the ‘-’ operator does nothing except spawn error messages wherever it is used.  Well, wherever it is used except the definition of that function.  Which type checks perfectly fine.  Uses of this version of ‘-’ will either fail type checking, throw up syntax errors, or both.  I’m mystified as to why this function definition actually type checks, when it it guaranteed to throw up errors when used.

Redefining how operators behave can be useful, but when it can *only* be an infix operator, why allow me to redefine it to take only one argument?  I discovered this mostly by accident reading library documentation and saying “hey, I wonder if this would work…”, so maybe there’s some additional syntax that can convert it to prefix or postfix?  Even so, why allow the infix version to be defined to take one argument, guaranteeing a noncallable function?

Advertisements

Functional Programming- Currying

Some confusing stuff, but I’m starting to see the potential.  

Currying is a technique that lets you define a function taking multiple arguments as a series of functions that take one argument, and returns a function that takes the rest.  You can define it all the way to the last argument.

This lets you call a funciton with fewer arguments than it takes, and fill in the extras later.  For instance, in SML, assuming powint takes two ints and returns the first int to the power of the second:

val p = powint 2

This makes p a function taking one argument, and giving you back the corresponding power of two.  Oh, you want powers of 10?

val p10 = powint 10

Next call, you have to do 3^5?  You can call it with both arguments right away if you want.

val p3_5 = powint 3 5

I’m still a bit confused on working with this, but the potential is very nice.

Always test functions before writing others that depend on them

Yeah.  Didn’t do that.  Now I have half a dozen functions, 50 or so lines of code, I have no idea if it works or not.  

At least I’ve traced this function as for sure not working.  And the other functions that it depends on are tested and work correctly.  So even if the rest are completely wrong, at least I’ve found a good starting point for debugging.

SML is odd

(if exp1 then exp2 else exp3) div (if exp4 then exp5 else exp6)

Is valid and for at least some problems, is entirely reasonable.

I think the key to SML, at least so far… *everything* is an expression.  Any complete statement returns a value, and anything that returns a value counts as an expression.  Ok, small exceptions here and there like, well, exceptions, but approaching it with “everything is an expression” has really helped my understanding.

Euclid algorithm for Greatest common Denominator, SML

fun gcd (x,y) = 
    if y = 0 then x 
    else gcd(y, x mod y)

I’ve wondered how to easily do this in code, without having to brute force it.  Turns out Euclid worked out the algorithm over 2,000 years ago.

Even if you aren’t a programmer, you can probably follow this code if you understand that “x mod y” gives you the remainder of x divided by y.  Then you need to understand recursion, but you’ll need to understand recursion first.

I don’t recall ever learning this technique in school.  It would have made some operations on fractions easier.

Project Euler problem 1- SML Implementation

Finished the current assignments and lectures for my Programming Languages course on Coursera, so I figured I’d go and do some other stuff in ML.  ML is a functional language, very heavy on recursion among other fun differences from imperative and OO languages.

Here’s a solution to Project Euler problem 1, summing all multiples of 3 and 5 that are below 1000.  

fun sum_multiples_3_5(limit : int) =

    if limit = 0

    then 0

    else if limit mod 3 = 0 orelse limit mod 5 = 0

           then limit + sum_multiples_3_5(limit-1)

           else sum_multiples_3_5(limit-1)

This is a general function, it will sum all multiples of 3 and 5 up through your limiting value.  If you want less than 1000, then, you’d call it:

sum_multiples_3_5(999);

The answer, in this case, is 233168.

I may generalize it further, taking a list of ints which are the factors you want multiples of.  That looks like a lot of extra work for something that is right now killing time because I can’t sleep, though, so I’ll be putting it off a bit.