|
 |
>>> BTW what would happen if I typed "choose 3 (-5)" instead?
>>
>> Well, it would execute
>>
>> (factorial 3) / (factorial (-5) * factorial (3 + 5))
>>
>> Given the above definition of factorial,
>>
>> factorial (-5) = product [1..-5] = product [] = 1
>>
>> Which I'm guessing means that choose gives the wrong answer.
>
> So what's the preferred way to cope with runtime "errors" like that? (I
> don't know if there is a technical term for such kind of errors that
> don't actually make an error, if you know what I mean).
The correct thing to do here would be
choose n k
| n < 0 = error "choose: negative n"
| k < 0 = error "choose: negative k"
| k > n = 0 -- According to Wikipedia.
| otherwise = (factorial n) `div` (factorial k * factorial (n - k))
(You would also define it to accept only unsigned integers as arguments,
which neatly does away with most of the error checking.)
> I suspect in a
> lot of case some very low nested function detects an error, and needs to
> signify this to a much higher level calling function (eg a "ParseFile"
> or "ParseLine" function or something).
The standard idiom in Haskell is this:
- If it's a program bug, use the "error" function. In particular, if a
function is called with invalid arguments, this is probably a bug in the
caller.
- If it's a routine, expected occurrance, return a data structure which
indicates success or failure. For example, a parse failure is totally to
be expected, so we need to explicitly handle it. The error is returned
"as data". (This is where the "error monad" comes in...)
The "error" function, technically speaking, throws an exception. Other
actions (generally only I/O operations) may also throw exceptions, and
Haskell has the usual exception-catching machinery. (Although things
like "catch" are library functions, not language constructs.)
> OK, so I could also do something like:
>
> data myRecord = myRecord {age :: Int, height :: Double, weight :: Double}
Yes, that'll work.
(Actually, I'm lying. The type name MUST begin with a capital letter.
This IS enforced by the compiler.)
The catch: Each field name is also a function name. Therefore, no two
types can have fields with the same name. (At least, not in the same
scope. Obviously types defined in different files can.) This restriction
becomes quite tedious at times.
>> Are all the cards the same suit?
>> length (group (map suit cards)) == 1
>> (This could be inefficient if "cards" is huge, but for a hand of 5 or
>> 7 cards, it should be fine.)
>>
>> First, you extract a list of suits.
>
> So in my example, if I had a list of myRecords, then "age MyList" would
> return a list of ages?
No. "map age mylist" would though. You need "map" to apply "age" to
every element of the list.
(And variable names MUST begin with a lowercase letter. The compiler
will complain if they don't.)
> What does the "map" do?
See above. ;-)
> OK so after Googling Haskell, implementations, GHC, go to the GHC page,
> latest release, "STOP!" they recommend I get the Haskell Platorm
> instead, oh goody a .exe installer link :-) I'll let you know in 54 MB
> time how I get on...
Yes, it's... a tad large. It *does* contain a complete copy of GCC, gas,
ld, perl.exe (?!) and a big suite of precompiled libraries, with HTML
documentation, a profiler, a debugger...
Background: Installing GHC used to give you a complete environment. But
the GHC guys don't want to maintain a complete environment, they want to
maintain GHC. So now the Haskell Platform exists, and the HP guys work
on HP, so the GHC guys can focus on just GHC. The idea is that HP will
grow to provide more stuff. Currently there's not actually much
difference. Follow all that?
Oh, and yes, GHC has *always* been big. You just want to play with
Haskell, but what you're downloading has all sorts of bells and whistles
that you won't use. There's a powerful parser library, cutting-edge
parallel processing technology, a complete OpenGL binding, POSIX
bindings, cross-platform filename processing... need I continue?
> Thing is it's very rare that I find myself wanting to write something
> that *I* think would be easier/faster with a language like Haskell.
Well, yes, it completely depends on the kind of code you want to write.
If you want to write, say, a computer game, Haskell probably isn't the
best choice. In C or C++, you can probably just download a game engine
and start coding. In Haskell... there's an OpenGL binding? I guess that
helps? But it's going to take a loooong time to get to a full-featured
game from there!
Personally, I tend to write crazy algorithm stuff. Haskell is great for
that, even if performance is a little unpredictable.
> But
> as I don't really know much about the language, I'm not a very good judge.
Well, yeah. That's kind of what's exciting about the web interpretter,
unfinished as it is. Now anybody can play with Haskell and do basic
stuff without... waiting for a 60+ MB download. ;-)
> You're also quite good a writing tutorials, you should definitely write
> a book. Haskell for Imperative Programmers. :-)
Heh. I've attempted to write *several* Haskell introductions. Roughly
once every 2 months I start writing a new one. They never get finished.
Trouble is, lots of Haskell's features depend on Haskell's other
features, so... where do you start? Which thing do you explain first? I
write an example, and then I go "oh crap, that uses X, I haven't even
mentioned that yet. Bugger!"
It's not complicated, it's just difficult to decide where to begin.
But thanks for your encouragement. Go take a look at the other thing I
just posted. ;-)
Post a reply to this message
|
 |