POV-Ray : Newsgroups : povray.off-topic : Current questions Server Time
31 Oct 2024 16:17:24 EDT (-0400)
  Current questions (Message 1 to 10 of 15)  
Goto Latest 10 Messages Next 5 Messages >>>
From: Orchid Win7 v1
Subject: Current questions
Date: 9 May 2013 15:54:13
Message: <518bfee5$1@news.povray.org>
I'm sure every programming language has them. But hanging out on Stack 
Overflow (and reading 8K rep by the way), I've noticed certain questions 
reappear with extreme frequency. For your amusement, I have attempted to 
collect the most common ones...

* Using tab characters instead of spaces.

Whitespace is used to delimit scope in Haskell. A space character is 1 
space wide; a tab character is a different randomly-chosen size in every 
program known to Man. That means that text which appears to line up in 
your text editor may look completely wrong in a different program - or 
to the Haskell compiler, for that matter.

This problem is nauseatingly hard to diagnose through a website. Usually 
when the person copy-pastes the code to the Internet, they inadvertently 
fix the actual problem in the pasted version.

* Other whitespace problems.

There are lots of other mistakes people make, where they write perfectly 
valid code which fails to compile merely because of an extra space here 
or there.

* Letter case errors.

Variable names MUST begin with a lower-case letter. Types and classes 
MUST begin with an upper-case letter. This is not merely a coding 
convention, it's actually how the compiler determines whether you're 
trying to access a variable or a type or whatever. So while C / C++ / C# 
/ Java / VB / whatever let you use any convention you please, in Haskell 
this can actually stop your program compiling at all - often with some 
very strange error messages.

* Missing out "else"

Haskell's if/then/else works like the ternary operator in C / C++. It is 
an EXPRESSION, not a STATEMENT. You CANNOT omit the else-clause; what 
would the value of the expression be if the test fails?

* Calling functions with tuples.

In anything derived from ALGOL, a function call looks like

   foo(1, 2, 3)

But in Haskell, the correct syntax is

   foo 1 2 3

This works exactly like Bash scripts; the first "word" is the function 
to call, and all subsequent words are arguments. This becomes slightly 
confusing because you can pass a function as an argument to another 
function. That means that the first word is the function to call, but 
the other words might ALSO be functions. Regardless, the FIRST word is 
always the function being called.

Unless it's an operator. (cf. 2 + 2)

Oh, and although words default to prefix and operators default to infix, 
you can override this. Very flexible, but also potentially confusing...

* Trying to make trees out of lists.

"I tried to write a function to convert [1, [2, 3], 4, [[5], [6, 7], 8], 
9] into [1, 2, 3, 4, 5, 6, 7, 8, 9], but I can't get it to compile."

The problem is nothing whatsoever to do with the actual code, it's the 
input. A variably-nested list like this is ILLEGAL in Haskell. It's 
ill-typed; every element of a list must have an identical type 
signature. And, naturally, integer /= list of integer /= list of list of 
integer.

* Incorrect let-block syntax.

The correct syntax for a let-block is

   let x = 1 in <expression>

However, inside a do-block it is permissible to write

   let x = 1

The REPL also accepts this form. But in a source file you can't write 
this outside of a do-block. This appears to be a common mistake. 
(Fortunately, it's one that's very easy to explain.)

* Incorrect where-block syntax

The correct syntax is

    ...stuff...
      where
        ...more stuff...

However, people keep trying to nest where-blocks. This is a bad idea; 
it's quite hard to get right, and it's not NECESSARY in the first place. 
[Usually.]

* Operator precedence mistakes.

This can bite you in any programming language. But a language that makes 
extensive use of large, complicated expressions is particularly 
troublesome. Examples:

Code:     putStrLn "Foo = " ++ show foo
Means:    (putStrLn "Foo") ++ (show foo)
Intended: putStrLn ("Foo" ++ (show foo))

Code:     sin 2*x
Means:    (sin 2)*x
Intended: sin (2*x)

Code:     print -2
Means:    print - 2    (I.e., subtract 2 from print.)
Intended: print (-2)   (I.e., print out -2.)

Notice how all three of these are the exact same bug; function 
application has the highest precedence of any operator, which apparently 
isn't what people are expecting. (The final example is arguably a bug in 
the language specification, but there you have it.)

* Detecting types at run-time.

"How do I write a function that takes one argument and detects whether 
it's a String or an Integer?"

Well, um, such a function can't exist in the first place? I mean, the 
type signature SPECIFIES exactly what type of value will be fed in at 
compile-time, so how could you not know at run-time?

A similar question is "how do I write a function that accepts any type 
of data and prints out its type?" Haskell simply doesn't support such 
things.

* Translating object-oriented code into Haskell.

"Hi. I tried to translate this [large] Java example into Haskell. I 
wrote <long tangled list of Haskell classes and datatypes>, but it 
doesn't compile / doesn't work. Help!"

Any programmer with any sense ought to realise that trying to 
"translate" code from one language to another which has a radically 
different paradigm is a very bad idea - ESPECIALLY for a beginner! If 
you're a Haskell expert, by all means give it a try. But if you're 
trying to learn the language for the first time, don't learn how to 
write bad Java code in Haskell, learn how to write Haskell code in Haskell!

(I would give the same advise to somebody trying to "translate" a 
Haskell program into Java. It's simpler to redesign from scratch.)

* Infinite loops

Recursion is very common in Haskell. A lot of people apparently don't 
understand how to make the recursion terminate eventually - perhaps they 
think this happens by magic or something. A definition such as

   map f (x:xs) = f x : map f xs

will throw a pattern-match failure exception when the end of the list is 
reached. But it's quite easy to do something like

   fibonacci n = fibonacci (n-1) + fibonacci (n-2)

This recursive loop simply never ends, exhausting all available RAM 
until the user has the sense to kill it. The fix isn't hard, but 
understanding the problem is apparently problematic for many.

* Monads.

"How do I convert IO Integer into Integer?"

Please go and read a basic tutorial explaining how I/O works in Haskell. 
(This particular question also seems to be particularly correlated with 
people who don't really understand Haskell syntax. I'm not sure why...)

* The "return" function.

In anything ALGOL-derived, the "return" keyword causes an immediate exit 
from the current function, optionally specifying a return value. In 
Haskell, it's not a keyword, it's a function, and it does something 
UTTERLY UNRELATED.

Namely, a monad is a thing that can produce a value, and "return x" 
constructs a monad which will produce x. This USUALLY happens at the end 
of a do-block, as in

   foobar a b c = do
     x <- foo a b
     y <- foo a c
     return (x + y)

But actually return is valid anywhere. One can write, for example,

   x <- return 5

which is the same as "x = 5".

It's not so much that what return does is confusing; merely that it's 
name leads people to expect it to work like other programming languages, 
when it's totally different. Simply renaming this function would 
probably fix the problem.

* Record name collisions.

In (say) C, you can write

   struct {int Foo, int Bar, int Baz} Foobar;
   struct {bool Foo, int Wok} Fizz;

Lots of people try to write Haskell like

   data Foobar = Foobar {foo :: Int, bar :: Int, baz :: Int}
   data Fizz = Fizz {foo :: Bool, wok :: Int}

This doesn't work at all, due to a namespace collision. Basically when 
you define a named field, it also auto-generates a function to fetch the 
value of that field. That is,

   foo :: Foobar -> Int
   bar :: Foobar -> Int
   ...etc...

Naturally, there can only be one function in scope named "foo". The net 
upshot of this is that no two records may ever have fields with the same 
name. This is widely considered a language design bug, but nobody has 
yet come up with a satisfactory solution to the problem.

* Special GHCi behaviour / defaulting rules / the monomorphism restriction.

GHCi, the Haskell REPL, behaves very slightly differently to how normal 
compiled Haskell works. You get lots of questions regarding strange 
differences in behaviour between code written in a source file, and code 
executed interactively. GHCi is slightly more forgiving, in the 
interests of letting you quickly test stuff without having to be really 
pedantic about everything; GHC demands that you say what you mean.

* Strictness bugs.

"I wrote this simple program, but when I give it more than a handful of 
inputs, it eats several GB of RAM and then crashes my PC!"

This is arguably the single greatest weakness of Haskell. It's 
frighteningly easy to write a program that defers huge amounts of work 
until the very last minute, and wastes vast amounts of RAM doing it. 
Often when you finally try to output a result, a stack overflow occurs 
as the run-time tries to recurse down a bazillion levels of indirection.

The fix for such bugs is sometimes frighteningly simple. I'm fond of the 
time I took one of my programs, added one single character to it, and it 
went from taking 20 minutes to taking 0.02 seconds to produce the same 
result. It's hard to make bugs of that magnitude in (say) Java or C++.

(On the other hand, sometimes the fix is terrifyingly difficult too!)

* Mutating data

"I deleted an item from this list, but it's still there!"

Um, no, no you did not.

"OK, so how do I do that?"

You can't. It's impossible. This is a design feature. Please go read 
about what functional programming is and why that's desirable.

* Writing a Haskell compiler.

"It's a simple beginner's exercise to write a simple Scheme interpreter. 
How hard would it be to write a Haskell REPL / compiler?"

Um, well, consider the following Haskell language features:
- Whitespace scoping.
- Arbitrary user-defined operators with user-defined precedence.
- Automatic type inference.
- Automatic code generation for system classes.
...yeah, er, this is not a five minute toy project. By all means, throw 
together something that parses and executes a small subset of Haskell. 
But if you want full Haskell 2010 compliance... yeah, that's gonna take 
you a little while.


Post a reply to this message

From: Warp
Subject: Re: Current questions
Date: 9 May 2013 16:07:22
Message: <518c01fa@news.povray.org>
Orchid Win7 v1 <voi### [at] devnull> wrote:
> * Other whitespace problems.

> There are lots of other mistakes people make, where they write perfectly 
> valid code which fails to compile merely because of an extra space here 
> or there.

Then perhaps it's a bad idea to create a programming language where
using one vs. multiple whitespace at some point makes a syntactic or
semantic difference.

-- 
                                                          - Warp


Post a reply to this message

From: Orchid Win7 v1
Subject: Re: Current questions
Date: 9 May 2013 16:21:27
Message: <518c0547@news.povray.org>
>> * Other whitespace problems.
>
>> There are lots of other mistakes people make, where they write perfectly
>> valid code which fails to compile merely because of an extra space here
>> or there.
>
> Then perhaps it's a bad idea to create a programming language where
> using one vs. multiple whitespace at some point makes a syntactic or
> semantic difference.

Perhaps. Most people seem OK once you explain that it's the whitespace 
that's causing their problem. Generally these same people don't make 
that particular mistake again.


Post a reply to this message

From: andrel
Subject: Re: Current questions
Date: 9 May 2013 16:43:14
Message: <518C0A60.7050305@gmail.com>
On 9-5-2013 22:07, Warp wrote:
> Orchid Win7 v1 <voi### [at] devnull> wrote:
>> * Other whitespace problems.
>
>> There are lots of other mistakes people make, where they write perfectly
>> valid code which fails to compile merely because of an extra space here
>> or there.
>
> Then perhaps it's a bad idea to create a programming language where
> using one vs. multiple whitespace at some point makes a syntactic or
> semantic difference.
>
obliatory reference:
http://en.wikipedia.org/wiki/Whitespace_(programming_language)

-- 
Women are the canaries of science. When they are underrepresented
it is a strong indication that non-scientific factors play a role
and the concentration of incorruptible scientists is also too low


Post a reply to this message

From: scott
Subject: Re: Current questions
Date: 10 May 2013 06:12:52
Message: <518cc824$1@news.povray.org>
>> Then perhaps it's a bad idea to create a programming language where
>> using one vs. multiple whitespace at some point makes a syntactic or
>> semantic difference.
>
> Perhaps. Most people seem OK once you explain that it's the whitespace
> that's causing their problem. Generally these same people don't make
> that particular mistake again.

Doesn't it prevent you adding in extra whitespace for readability? That 
seems like quite a limitation.


Post a reply to this message

From: Orchid Win7 v1
Subject: Re: Current questions
Date: 10 May 2013 16:39:09
Message: <518d5aed@news.povray.org>
On 10/05/2013 11:12 AM, scott wrote:
>>> Then perhaps it's a bad idea to create a programming language where
>>> using one vs. multiple whitespace at some point makes a syntactic or
>>> semantic difference.
>>
>> Perhaps. Most people seem OK once you explain that it's the whitespace
>> that's causing their problem. Generally these same people don't make
>> that particular mistake again.
>
> Doesn't it prevent you adding in extra whitespace for readability? That
> seems like quite a limitation.

Not really.

It's not like the rule says "you must have exactly X characters of 
whitespace here, and Y characters of whitespace there".

It's only line ends and indentation that carry any special significance. 
The whitespace within the length of the line can work any way you fancy. 
And the rule about indentation is just that nested scopes must be 
indented further than the outer scope. the rule doesn't say by how much; 
that's up to you.

It's not like, say, Makefiles, where you MUST use tab characters or it 
doesn't work right. (I always thought that was absurdly stupid...)


Post a reply to this message

From: Orchid Win7 v1
Subject: Re: Current questions
Date: 10 May 2013 16:41:29
Message: <518d5b79$1@news.povray.org>
On 09/05/2013 09:43 PM, andrel wrote:
> obliatory reference:
> http://en.wikipedia.org/wiki/Whitespace_(programming_language)

"The idea of using whitespace characters as operators for the C++ 
language was facetiously suggested five years earlier by Bjarne Stroustrup."

Well, in a way, whitespace *is* an operator in Haskell. Or rather, 
function application is an operator (it even has an operator 
precedence), and function application is denoted by whitespace in Haskell.

In other way, inside a do-block, every end of line is replaced by the 
">>" or ">>=" operator. So end of line is a bit like an operator. 
(Although you can write explicit ";" characters if you prefer.)


Post a reply to this message

From: clipka
Subject: Re: Current questions
Date: 11 May 2013 15:23:57
Message: <518e9acd$1@news.povray.org>
Am 09.05.2013 21:54, schrieb Orchid Win7 v1:

> * Using tab characters instead of spaces.
>
> Whitespace is used to delimit scope in Haskell. A space character is 1
> space wide; a tab character is a different randomly-chosen size in every
> program known to Man. That means that text which appears to line up in
> your text editor may look completely wrong in a different program - or
> to the Haskell compiler, for that matter.

... which is why placing importance on indentation in a programming 
language constitutes a design flaw...


> * Calling functions with tuples.
>
> In anything derived from ALGOL, a function call looks like
>
>    foo(1, 2, 3)
>
> But in Haskell, the correct syntax is
>
>    foo 1 2 3
>
> This works exactly like Bash scripts; the first "word" is the function
> to call, and all subsequent words are arguments. This becomes slightly
> confusing because you can pass a function as an argument to another
> function. That means that the first word is the function to call, but
> the other words might ALSO be functions. Regardless, the FIRST word is
> always the function being called.

I think this is actually a pretty stupid notation for a functional 
programming language; after all, the braced notation is /the/ 
traditional notation for functions in mathematics.

I'd go even further and question the whole concept of passing multiple 
arguments to a function. You can't output multiple values from a 
function (unless using a tuple), so why should you input multiple values 
(unless using a tuple)?


> Code:     print -2
> Means:    print - 2    (I.e., subtract 2 from print.)
> Intended: print (-2)   (I.e., print out -2.)
>
> Notice how all three of these are the exact same bug; function
> application has the highest precedence of any operator, which apparently
> isn't what people are expecting. (The final example is arguably a bug in
> the language specification, but there you have it.)

I wouldn't call the latter case a bug in the language spec. It's the 
whole idea of making function application have highest precedence that 
I'd call a bug.

BTW this wouldn't be a problem if Haskell used the classic "fn(x,y,z)" 
notation for functions.


> Lots of people try to write Haskell like
>
>    data Foobar = Foobar {foo :: Int, bar :: Int, baz :: Int}
>    data Fizz = Fizz {foo :: Bool, wok :: Int}
>
> This doesn't work at all, due to a namespace collision. Basically when
> you define a named field, it also auto-generates a function to fetch the
> value of that field. That is,
>
>    foo :: Foobar -> Int
>    bar :: Foobar -> Int
>    ...etc...
>
> Naturally, there can only be one function in scope named "foo". The net
> upshot of this is that no two records may ever have fields with the same
> name. This is widely considered a language design bug, but nobody has
> yet come up with a satisfactory solution to the problem.

A /severe/ design bug, if I'm asked. Nothing I'd expect from a 
contemporary programming language.


Post a reply to this message

From: Warp
Subject: Re: Current questions
Date: 11 May 2013 15:46:13
Message: <518ea005@news.povray.org>
clipka <ano### [at] anonymousorg> wrote:
> I'd go even further and question the whole concept of passing multiple 
> arguments to a function. You can't output multiple values from a 
> function (unless using a tuple), so why should you input multiple values 
> (unless using a tuple)?

There's basically no difference between binary operators and functions
in mathematics. A binary operator is, basically, a function taking two
values and returning one.

I don't think it's in any way incorrect in mathematics to use a function
notation for binary (or ternary, etc.) operations.

-- 
                                                          - Warp


Post a reply to this message

From: Orchid Win7 v1
Subject: Re: Current questions
Date: 11 May 2013 17:21:15
Message: <518eb64b$1@news.povray.org>
>> Whitespace is used to delimit scope in Haskell. A space character is 1
>> space wide; a tab character is a different randomly-chosen size in every
>> program known to Man.
>
> ... which is why placing importance on indentation in a programming
> language constitutes a design flaw...

Well, you can say that if you wish. I'm not going to agree with you 
though. :-P

It's really quite irritating to have your program not compile just 
because you accidentally left out a semicolon with it's damned obvious 
what you actually meant. Haskell means I never have to worry about this.

>> * Calling functions with tuples.
>>
>> In anything derived from ALGOL, a function call looks like
>>
>> foo(1, 2, 3)
>>
>> But in Haskell, the correct syntax is
>>
>> foo 1 2 3
>
> I think this is actually a pretty stupid notation for a functional
> programming language; after all, the braced notation is /the/
> traditional notation for functions in mathematics.

No, no it is not.

Consider, for example, Euler's relation. It is customarily written as

   exp ix = cos x + i sin x

It is NOT typically written as

   exp(ix) = cos(x) + i sin(x)

except when written in computer source code.

> I'd go even further and question the whole concept of passing multiple
> arguments to a function. You can't output multiple values from a
> function (unless using a tuple), so why should you input multiple values
> (unless using a tuple)?

That is a whole other question, of course.

There are plenty of standard mathematical functions which take multiple 
arguments. (GCD, anyone?) When it comes to computers, there is a simple 
and easy way of implementing passing multiple bits of data to a 
subroutine at once; if anything, the strange thing is that nobody has 
come up with a programming language that lets you RETURN several items 
at once. At the machine level, this would be a very easy thing to 
implement. I can only imagine it's because nobody has come up with a 
nice notation for writing it...

>> Code: print -2
>> Means: print - 2 (I.e., subtract 2 from print.)
>> Intended: print (-2) (I.e., print out -2.)
>>
>> Notice how all three of these are the exact same bug; function
>> application has the highest precedence of any operator, which apparently
>> isn't what people are expecting. (The final example is arguably a bug in
>> the language specification, but there you have it.)
>
> I wouldn't call the latter case a bug in the language spec. It's the
> whole idea of making function application have highest precedence that
> I'd call a bug.

Consider, for example, the expression

   tan x = cos x / sin x

Here operator precedence does EXACTLY what we want it to do. Consider 
another example:

   string = printf "%x" value1 ++ show value2 ++ unlines list3

Here, again, we concatenate the output from several different functions 
into a single string, and operator precedence works exactly how we want 
it to, without needing any brackets.

I suspect that basically for any possible choice of precedences, you 
will nearly always be able to find an example where it doesn't work how 
you'd like it to. Never the less, I think the current operator 
precedences work pretty well.

> BTW this wouldn't be a problem if Haskell used the classic "fn(x,y,z)"
> notation for functions.

That's true. But then again, remember that Haskell allows you to call a 
function with a different number of arguments than the function expects. 
That's probably the main reason why it doesn't use that syntax.

>> Lots of people try to write Haskell like
>>
>> data Foobar = Foobar {foo :: Int, bar :: Int, baz :: Int}
>> data Fizz = Fizz {foo :: Bool, wok :: Int}
>>
>> This doesn't work at all, due to a namespace collision.
>
> A /severe/ design bug, if I'm asked. Nothing I'd expect from a
> contemporary programming language.

It's embarrassing, sure. But it's not really an especially severe bug; 
it's just a nuisance having to manually prefix all your field names with 
the name of the type that they belong to (or some abbreviation thereof).


Post a reply to this message

Goto Latest 10 Messages Next 5 Messages >>>

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