POV-Ray : Newsgroups : povray.off-topic : Try Haskell : Re: Try Haskell Server Time
4 Sep 2024 17:22:41 EDT (-0400)
  Re: Try Haskell  
From: Invisible
Date: 4 Mar 2010 06:16:57
Message: <4b8f96a9$1@news.povray.org>
>>> 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

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.