"where" block local to a guard?
Hi, Suppose you have some function functn :: Int -> Int functn i | i>5 = t * i | i>0 = t_ * i | otherwise = 1 where t = functn (i-2) t_ = functn (i-1) Notice that t and t_ are really local to a guard, rather than to the whole guard section. Why then, can't you write: functn :: Int -> Int functn i | i>5 = t * i where t = functn (i-2) | i>0 = t * i where t = functn (i-1) | otherwise = 1 In particular, the above would mean you wouldn't need two names t and t_, you could just use t for both! Am I doing something wrongly, or is there a good reason why where isn't allowed to be used in this way? Thanks, Mark. -- Dr Mark H Phillips Research Analyst (Mathematician) AUSTRICS - smarter scheduling solutions - www.austrics.com Level 2, 50 Pirie Street, Adelaide SA 5000, Australia Phone +61 8 8226 9850 Fax +61 8 8231 4821 Email mark@austrics.com.au
Dr Mark H Phillips wrote:
Hi,
Suppose you have some function
functn :: Int -> Int functn i | i>5 = t * i | i>0 = t_ * i | otherwise = 1 where t = functn (i-2) t_ = functn (i-1)
Notice that t and t_ are really local to a guard, rather than to the whole guard section. Why then, can't you write:
functn :: Int -> Int functn i | i>5 = t * i where t = functn (i-2) | i>0 = t * i where t = functn (i-1) | otherwise = 1
In particular, the above would mean you wouldn't need two names t and t_, you could just use t for both!
Am I doing something wrongly, or is there a good reason why where isn't allowed to be used in this way?
You can't do this because where clauses are not part of the expression syntax. If they were, expressions like let a=b in c where d=e or if a then b else c where d=e whould be ambiguous, unless you adopt arbitrary rules about the prededences, and such arbitrary rules are considered a bad thing. Very early on in the design of Haskell, the issue of how to deal with the two alternative styles for local definitions (let and where) was resolved by only allowing let in the expression syntax, but allowing where as part of the equation syntax. The nice thing about this is that, apart from removing ambiguities in expressions, where syntax provides a way of writing definitions which span several guarded right-hand-sides, and in the simple case of a single rhs, looks just like a where expression, so allows people to write effectively in that style. --brian -- Brian Boutel Wellington New Zealand
Thanks for the explanation! On Tue, 2002-09-17 at 19:07, Brian Boutel wrote:
You can't do this because where clauses are not part of the expression syntax. If they were, expressions like
let a=b in c where d=e or if a then b else c where d=e
whould be ambiguous, unless you adopt arbitrary rules about the prededences, and such arbitrary rules are considered a bad thing.
I'm trying to see how ambiguity might arise. Do you mean something like: let a=1 in a+a where a=3 or have you something different in mind? And I can't yet think of a situation where if a then b else c where d=e would cause problems. Cheers, Mark.
Dr Mark H Phillips wrote:
Thanks for the explanation!
On Tue, 2002-09-17 at 19:07, Brian Boutel wrote:
You can't do this because where clauses are not part of the expression syntax. If they were, expressions like
let a=b in c where d=e or if a then b else c where d=e
whould be ambiguous, unless you adopt arbitrary rules about the prededences, and such arbitrary rules are considered a bad thing.
I'm trying to see how ambiguity might arise. Do you mean something like:
let a=1 in a+a where a=3
Yes.
or have you something different in mind?
And I can't yet think of a situation where
if a then b else c where d=e
would cause problems.
The question is whether the local definition of d scopes over the whole conditional expression, or just over the else part. As in if a then d else 2*d where d==e Is the first d the one defined in the where, or one from an enclosing declaration? It's instructive to write a grammar quite abstractly, with rules like exp <- if exp then exp else exp | let decls in exp | exp where decls | ... decls <- decl | decl decls decl <- var = exp and then feed this into a parser generator like yacc, and look at the conflicts it generates. Each one has to be resolved by a shift or reduce decision, or possibly a choice between two reduces, but whichever is chosen, code written on a mistaken assumption will still compile but produce a semantically incorrect program. --brian -- Brian Boutel Wellington New Zealand
At 3:07 PM +0930 9/17/02, Dr Mark H Phillips wrote:
Suppose you have some function
functn :: Int -> Int functn i | i>5 = t * i | i>0 = t_ * i | otherwise = 1 where t = functn (i-2) t_ = functn (i-1)
Notice that t and t_ are really local to a guard, rather than to the whole guard section. Why then, can't you write:
functn :: Int -> Int functn i | i>5 = t * i where t = functn (i-2) | i>0 = t * i where t = functn (i-1) | otherwise = 1
In particular, the above would mean you wouldn't need two names t and t_, you could just use t for both!
Am I doing something wrongly, or is there a good reason why where isn't allowed to be used in this way?
You can get the effect you're after by using let-expressions:
functn :: Int -> Int functn i | i>5 = let t = functn (i-2) in t * i | i>0 = let t = functn (i-1) in t * i | otherwise = 1
'where' is part of the syntax of definitions, not expressions. This enables a name defined in a where-clause to be used in more than one guarded expression. --Ham -- ------------------------------------------------------------------ Hamilton Richards Department of Computer Sciences Senior Lecturer The University of Texas at Austin 512-471-9525 1 University Station C0500 Taylor Hall 5.138 Austin, Texas 78712-1188 ham@cs.utexas.edu hrichrds@swbell.net ------------------------------------------------------------------
On Wed, 2002-09-18 at 01:26, Hamilton Richards wrote:
You can get the effect you're after by using let-expressions:
functn :: Int -> Int functn i | i>5 = let t = functn (i-2) in t * i | i>0 = let t = functn (i-1) in t * i | otherwise = 1
'where' is part of the syntax of definitions, not expressions. This enables a name defined in a where-clause to be used in more than one guarded expression.
Thanks for this! It would seem "let ... in ..." is what I want. But I'm a bit confused about how to use the off-side rule in conjunction with let. Do I do: let a=1 b=2 c=3 in a*b*c or do I do: let a=1 b=2 c=3 in a*b*c or, in the context of a guard, do I do: | i>5 = let a=1; b=2; c=3 in a*b*c Basically I'm a bit confused about how the offside rule works in various situations. With "if ... then ... else ..." I don't know whether I should be doing f x = if x>5 then x*x else 2*x or f x = if x>5 then x*x else 2*x or f x = if x>5 then x*x else 2*x or what! Hugs seems to think they are all legal. Is there any rational as to how to do layout? Any tips would be greatly appreciated! Thanks, Mark.
I think this is purely a personal taste kind of thing. First off, though, only 'where', 'let', 'of' and 'do' induce layout. I've seen many layout styles; the most common seem to be: let x = ... y = ... z = ... in e which is probably a carryover from ML like languages where you might have to say let x = ... let y = ... let z = ... in e sometimes "e" doesn't have two spaces before it and sometimes the "in" is indented an extra space. it also seems to be fairly common to put the "in" on the end of the last line in the local definitions. 'where' seems to be less variable. by far the most common of what i've seen in: where x = ... y = ... but i've also seen where x = ... y = ... the advantage here is that its very easy to remove the 'x' definition without having to reorder other things. there seem to be two things people do with 'do'. the first is obvious: do x ... y ... z ... but another common one (esp in the ghc code) is: myfunction = do x ... y ... z ... which i've recently become fond of. with case/of, the most common seems to be: case x of y -> ... abc -> ... but the indentations vary by user. if/then/else seems to be highly variable. i personally like if foo then bar else baz but opinions are likely to vary widely. likely, |{different offered layout options}| >= |{people who respond to this email}|, though, so take anything with a grain of sand. - hal -- Hal Daume III "Computer science is no more about computers | hdaume@isi.edu than astronomy is about telescopes." -Dijkstra | www.isi.edu/~hdaume On 18 Sep 2002, Dr Mark H Phillips wrote:
On Wed, 2002-09-18 at 01:26, Hamilton Richards wrote:
You can get the effect you're after by using let-expressions:
functn :: Int -> Int functn i | i>5 = let t = functn (i-2) in t * i | i>0 = let t = functn (i-1) in t * i | otherwise = 1
'where' is part of the syntax of definitions, not expressions. This enables a name defined in a where-clause to be used in more than one guarded expression.
Thanks for this! It would seem "let ... in ..." is what I want.
But I'm a bit confused about how to use the off-side rule in conjunction with let. Do I do:
let a=1 b=2 c=3 in a*b*c
or do I do:
let a=1 b=2 c=3 in a*b*c
or, in the context of a guard, do I do:
| i>5 = let a=1; b=2; c=3 in a*b*c
Basically I'm a bit confused about how the offside rule works in various situations.
With "if ... then ... else ..." I don't know whether I should be doing
f x = if x>5 then x*x else 2*x
or
f x = if x>5 then x*x else 2*x
or
f x = if x>5 then x*x else 2*x
or what!
Hugs seems to think they are all legal. Is there any rational as to how to do layout? Any tips would be greatly appreciated!
Thanks,
Mark.
_______________________________________________ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell
On Wednesday, 2002-09-18, 07:22, CEST, Hal Daume III wrote:
I think this is purely a personal taste kind of thing. First off, though, only 'where', 'let', 'of' and 'do' induce layout. I've seen many layout styles; the most common seem to be:
let x = ... y = ... z = ... in e
which is probably a carryover from ML like languages where you might have to say
let x = ... let y = ... let z = ... in e
sometimes "e" doesn't have two spaces before it and sometimes the "in" is indented an extra space.
it also seems to be fairly common to put the "in" on the end of the last line in the local definitions.
'where' seems to be less variable. by far the most common of what i've seen in:
where x = ... y = ...
but i've also seen
where x = ... y = ...
the advantage here is that its very easy to remove the 'x' definition without having to reorder other things.
there seem to be two things people do with 'do'. the first is obvious:
do x ... y ... z ...
but another common one (esp in the ghc code) is:
myfunction = do x ... y ... z ...
which i've recently become fond of.
with case/of, the most common seems to be:
case x of y -> ... abc -> ...
but the indentations vary by user.
if/then/else seems to be highly variable. i personally like
if foo then bar else baz
but opinions are likely to vary widely.
likely, |{different offered layout options}| >= |{people who respond to this email}|, though, so take anything with a grain of sand.
- hal
-- Hal Daume III
"Computer science is no more about computers | hdaume@isi.edu than astronomy is about telescopes." -Dijkstra | www.isi.edu/~hdaume
On 18 Sep 2002, Dr Mark H Phillips wrote:
On Wed, 2002-09-18 at 01:26, Hamilton Richards wrote:
You can get the effect you're after by using let-expressions:
functn :: Int -> Int functn i | i>5 = let t = functn (i-2) in t * i | i>0 = let t = functn (i-1) in t * i | otherwise = 1
'where' is part of the syntax of definitions, not expressions. This enables a name defined in a where-clause to be used in more than one guarded expression.
Thanks for this! It would seem "let ... in ..." is what I want.
But I'm a bit confused about how to use the off-side rule in conjunction with let. Do I do:
let a=1 b=2 c=3 in a*b*c
or do I do:
let a=1 b=2 c=3 in a*b*c
or, in the context of a guard, do I do:
| i>5 = let a=1; b=2; c=3 in a*b*c
Basically I'm a bit confused about how the offside rule works in various situations.
With "if ... then ... else ..." I don't know whether I should be doing
f x = if x>5 then x*x else 2*x
or
f x = if x>5 then x*x else 2*x
or
f x = if x>5 then x*x else 2*x
or what!
Hugs seems to think they are all legal. Is there any rational as to how to do layout? Any tips would be greatly appreciated!
Thanks,
Mark.
Hi, I prefer the following styles: for let statements: let variable1 :: type1 variable1 = expression1 variable2 :: type2 variable2 = expression2 in expression for where clauses: where variable1 :: type1 variable1 = expression1 variable2 :: type2 variable1 = expression2 for do statements: do variable1 <- expression1 variable2 <- expression2 expression for case statements: case expression of pattern1 -> expression1 pattern2 -> expression2 or, if lines would get too long, case expression of pattern1 -> expression1 pattern2 -> expression2 for if statements: if expression then texpression else eexpression Wolfgang
participants (5)
-
Brian Boutel -
Dr Mark H Phillips -
Hal Daume III -
Hamilton Richards -
Wolfgang Jeltsch