
12

I'd also say that reading commandline flags inside a simple function like amount is a pretty large code smell. The only case in which it isn't would be when the codebase is so small that redesigning the Haskell to be in IO (or switch between amountPlus and amountTimes) is negligible anyway.
On Jun 26, 2012, at 18:59, Ozgun Ataman < [hidden email]> wrote:
We could debate this endlessly (as is common), but I would argue that a "clean" design would make the option and alternative of multiplying explicit in its design instead of including calls to fetch command line arguments in an adhoc fashion everywhere.
The Haskell way of encoding this would be to define an app configuration data type (say AppConfig), parse the command line arguments into it upfront in IO and then run your application either in a in a monad that's an instance of (MonadReader MyConfig) or explicitly pass the option in where needed by a function. If you've designed your application this way, adding a new command line option would cause very little if any refactoring. If not, in my experience it is usually a 30 minute intense refactoring campaign.
I suspect there might be a way to use implicit arguments here as well, but that's something I've never felt compelled to use.
This kind of separation of concerns and "pure" application design is one of the things that (I think) many people really like about Haskell.
Cheers, Oz
On Tuesday, June 26, 2012 at 6:19 PM, Tillmann Rendel wrote:
Hi,
MightyByte wrote: Of course every line of your program that uses a Foo will change if you switch to IO Foo instead.
But we often have to also change lines that don't use Foo at all. For example, here is the type of binary trees of integers:
data Tree = Leaf Integer  Branch (Tree Integer) (Tree Integer)
A function to add up all integers in a tree:
amount:: Tree > Integer amount (Leaf x) = x amount (Branch t1 t2) = amountt1 + amountt2
All fine so far. Now, consider the following additional requirement: "If the commandline flag multiply is set, the function amount computes the product instead of the sum."
In a language with implicit side effects, it is easy to implement this. We just change the third line of the amount function to check whether to call (+) or (*). In particular, we would not touch the other two lines.
How would you implement this requirement in Haskell without changing the line "amount (Leaf x) = x"?
(I actually see three ways of doing this in Haskell, but all have
serious drawbacks and do not fully solve the problem).
Here it seems not so bad just to change all three lines of the amount function, even if they are not strictly related to the semantic change
we want to make. But in a real program, this situation can translate to changing thousands of lines of code in many functions just to implement a minor change to a single requirement.
Tillmann
_______________________________________________ HaskellCafe mailing list
_______________________________________________
HaskellCafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskellcafe


On Tue, Jun 26, 2012 at 3:19 PM, Tillmann Rendel
< [hidden email]> wrote:
> A function to add up all integers in a tree:
>
> amount:: Tree > Integer
> amount (Leaf x) = x
> amount (Branch t1 t2) = amountt1 + amountt2
>
> All fine so far. Now, consider the following additional requirement: "If the
> commandline flag multiply is set, the function amount computes the
> product instead of the sum."
>
> How would you implement this requirement in Haskell without changing the
> line "amount (Leaf x) = x"?
One option is to encode the desired behavior at the type level. By
extended the data type slightly and adding a Functor instance,
selecting between a product and a sum can be done using their Monoid
newtypes:
import Data.Monoid
import System.Environment
data Tree a = Leaf a  Branch (Tree a) (Tree a)
instance Functor Tree where
f `fmap` Leaf x = Leaf (f x)
f `fmap` Branch x y = Branch (fmap f x) (fmap f y)
amount :: Monoid a => Tree a > a
amount (Leaf x) = x
amount (Branch t1 t2) = amount t1 <> amount t2
main :: IO ()
main = do
args < getArgs
let val :: Tree Int
val = Branch (Leaf 8) (Leaf 18)
let getResult :: Tree Int > Int
getResult = case args of
["multiply"] > getProduct . amount . fmap Product
_ > getSum . amount . fmap Sum
print . getResult $ val
_______________________________________________
HaskellCafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskellcafe


Hi Rico,
Rico Moorman wrote:
>> data Tree = Leaf Integer  Branch (Tree Integer) (Tree Integer)
>>
>> amount:: Tree > Integer
>> amount (Leaf x) = x
>> amount (Branch t1 t2) = amountt1 + amountt2
>>
>> [...] additional requirement: "If the commandline flag multiply is set,
>> the function amount computes the product instead of the sum."
>>
>> How would you implement this requirement in Haskell without changing the
>> line "amount (Leaf x) = x"?
> The (for me at least) most obvious way to do this would be, to make the
> operation to be applied to determine the amount (+ or *) an explicit
> parameter in the function's definition.
>
> data Tree a = Leaf a
>  Branch (Tree a) (Tree a)
> amount :: (a > a > a) > Tree a > a
> amount fun (Leaf x) = x
> amount fun (Branch t1 t2) = amount fun t1 `fun` amount fun t2
I agree: This is the most obvious way, and also a very good way. I would
probably do it like this.
> Which drawbacks do you see besides increased verbosity?
Well, you did change the equation "amount (Leaf x) = x" to "amount fun
(Leaf x) = x". In a larger example, this means that you need to change
many lines of many functions, just to get the the value of fun from the
point where it is known to the point where you need it.
> [...] I am wondering which ways of doing this in Haskell you mean.
I thought of the following three options, but see also Nathan Howells
email for another alternative (that is related to my option (1) below):
(1) Implicit parameters:
{# LANGUAGE ImplicitParams #}
data Tree = Leaf Integer  Branch Tree Tree
amount :: (?fun :: Integer > Integer > Integer) => Tree > Integer
amount (Leaf x) = x
amount (Branch t1 t2) = ?fun (amount t1) (amount t2)
(2) Lexical Scoping:
data Tree = Leaf Integer  Branch Tree Tree
amount :: (Integer > Integer > Integer) > Tree > Integer
amount fun = amount where {
amount (Leaf x) = x
; amount (Branch t1 t2) = fun (amount t1) (amount t2) }
(3) UnsafePerformIO:
import System.IO.Unsafe (unsafePerformIO)
data Tree = Leaf Integer  Branch Tree Tree
amount :: Tree > Integer
amount (Leaf x) = x
amount (Branch t1 t2) = fun (amount t1) (amount t2)
where fun = unsafePerformIO ...
I'm not happy with any of these options. Personally, I would probably go
ahead and transform the whole program just to get the value of fun to
where it is needed. Nevertheless, having actually done this before, I
understand why Martin Odersky doesn't like doing it :)
Tillmann
_______________________________________________
HaskellCafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskellcafe


> I'm not happy with any of these options. Why are you unhappy with the ImplicitParams option? It's pretty much like resorting to a newtype, as it's been suggested before.
2012/6/27 Tillmann Rendel <[hidden email]>
Hi Rico,
Rico Moorman wrote:
data Tree = Leaf Integer  Branch (Tree Integer) (Tree Integer)
amount:: Tree > Integer
amount (Leaf x) = x
amount (Branch t1 t2) = amountt1 + amountt2
[...] additional requirement: "If the commandline flag multiply is set,
the function amount computes the product instead of the sum."
How would you implement this requirement in Haskell without changing the
line "amount (Leaf x) = x"?
The (for me at least) most obvious way to do this would be, to make the
operation to be applied to determine the amount (+ or *) an explicit
parameter in the function's definition.
data Tree a = Leaf a
 Branch (Tree a) (Tree a)
amount :: (a > a > a) > Tree a > a
amount fun (Leaf x) = x
amount fun (Branch t1 t2) = amount fun t1 `fun` amount fun t2
I agree: This is the most obvious way, and also a very good way. I would probably do it like this.
Which drawbacks do you see besides increased verbosity?
Well, you did change the equation "amount (Leaf x) = x" to "amount fun (Leaf x) = x". In a larger example, this means that you need to change many lines of many functions, just to get the the value of fun from the point where it is known to the point where you need it.
[...] I am wondering which ways of doing this in Haskell you mean.
I thought of the following three options, but see also Nathan Howells email for another alternative (that is related to my option (1) below):
(1) Implicit parameters:
{# LANGUAGE ImplicitParams #}
data Tree = Leaf Integer  Branch Tree Tree
amount :: (?fun :: Integer > Integer > Integer) => Tree > Integer
amount (Leaf x) = x
amount (Branch t1 t2) = ?fun (amount t1) (amount t2)
(2) Lexical Scoping:
data Tree = Leaf Integer  Branch Tree Tree
amount :: (Integer > Integer > Integer) > Tree > Integer
amount fun = amount where {
amount (Leaf x) = x
; amount (Branch t1 t2) = fun (amount t1) (amount t2) }
(3) UnsafePerformIO:
import System.IO.Unsafe (unsafePerformIO)
data Tree = Leaf Integer  Branch Tree Tree
amount :: Tree > Integer
amount (Leaf x) = x
amount (Branch t1 t2) = fun (amount t1) (amount t2)
where fun = unsafePerformIO ...
I'm not happy with any of these options. Personally, I would probably go ahead and transform the whole program just to get the value of fun to where it is needed. Nevertheless, having actually done this before, I understand why Martin Odersky doesn't like doing it :)
_______________________________________________
HaskellCafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskellcafe


The "problem" of monads is that it defines different execution models, besides the funcional,/lazy/declarative mode. There is no such problem in imperative languages, which work ever in an hardwired IO monad. But this means that the programmer has to code the extra behaviour needed in each application to do the same.
It pretend to be intuitive, not accurate. (See disclaimer ;) . Comments welcome
2012/6/27 Yves Parès <[hidden email]>
> I'm not happy with any of these options.
Why are you unhappy with the ImplicitParams option?
It's pretty much like resorting to a newtype, as it's been suggested before.
2012/6/27 Tillmann Rendel <[hidden email]>
Hi Rico,
Rico Moorman wrote:
data Tree = Leaf Integer  Branch (Tree Integer) (Tree Integer)
amount:: Tree > Integer
amount (Leaf x) = x
amount (Branch t1 t2) = amountt1 + amountt2
[...] additional requirement: "If the commandline flag multiply is set,
the function amount computes the product instead of the sum."
How would you implement this requirement in Haskell without changing the
line "amount (Leaf x) = x"?
The (for me at least) most obvious way to do this would be, to make the
operation to be applied to determine the amount (+ or *) an explicit
parameter in the function's definition.
data Tree a = Leaf a
 Branch (Tree a) (Tree a)
amount :: (a > a > a) > Tree a > a
amount fun (Leaf x) = x
amount fun (Branch t1 t2) = amount fun t1 `fun` amount fun t2
I agree: This is the most obvious way, and also a very good way. I would probably do it like this.
Which drawbacks do you see besides increased verbosity?
Well, you did change the equation "amount (Leaf x) = x" to "amount fun (Leaf x) = x". In a larger example, this means that you need to change many lines of many functions, just to get the the value of fun from the point where it is known to the point where you need it.
[...] I am wondering which ways of doing this in Haskell you mean.
I thought of the following three options, but see also Nathan Howells email for another alternative (that is related to my option (1) below):
(1) Implicit parameters:
{# LANGUAGE ImplicitParams #}
data Tree = Leaf Integer  Branch Tree Tree
amount :: (?fun :: Integer > Integer > Integer) => Tree > Integer
amount (Leaf x) = x
amount (Branch t1 t2) = ?fun (amount t1) (amount t2)
(2) Lexical Scoping:
data Tree = Leaf Integer  Branch Tree Tree
amount :: (Integer > Integer > Integer) > Tree > Integer
amount fun = amount where {
amount (Leaf x) = x
; amount (Branch t1 t2) = fun (amount t1) (amount t2) }
(3) UnsafePerformIO:
import System.IO.Unsafe (unsafePerformIO)
data Tree = Leaf Integer  Branch Tree Tree
amount :: Tree > Integer
amount (Leaf x) = x
amount (Branch t1 t2) = fun (amount t1) (amount t2)
where fun = unsafePerformIO ...
I'm not happy with any of these options. Personally, I would probably go ahead and transform the whole program just to get the value of fun to where it is needed. Nevertheless, having actually done this before, I understand why Martin Odersky doesn't like doing it :)
_______________________________________________
HaskellCafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskellcafe
_______________________________________________
HaskellCafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskellcafe


Tillmann Rendel <rendel <at> informatik.unimarburg.de> writes:
>
> > Which drawbacks do you see besides increased verbosity?
>
> Well, you did change the equation "amount (Leaf x) = x" to "amount fun
> (Leaf x) = x". In a larger example, this means that you need to change
> many lines of many functions, just to get the the value of fun from the
> point where it is known to the point where you need it.
I would argue that no matter how good one's language is, there will always exist
realistic refactorings that require you to make sweeping changes to a large
portion of your code base.
> > [...] I am wondering which ways of doing this in Haskell you mean.
>
> I thought of the following three options, but see also Nathan Howells
> email for another alternative (that is related to my option (1) below):
>
> (1) Implicit parameters:
<snip>
> (2) Lexical Scoping:
<snip>
> (3) UnsafePerformIO:
<snip>
> I'm not happy with any of these options. Personally, I would probably go
> ahead and transform the whole program just to get the value of fun to
> where it is needed. Nevertheless, having actually done this before, I
> understand why Martin Odersky doesn't like doing it :)
I think that Martin's statement is an unavoidable fact of life that follows
directly from the definition of purity and the mechanics of data dependencies.
Of course nobody likes making sweeping changes to their app because they didn't
anticipate the way the future would evolve. But lets not blame monads for what
is really a much more fundamental phenomenon.
_______________________________________________
HaskellCafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskellcafe


On 26/06/2012, Nathan Howell < [hidden email]> wrote:
> On Tue, Jun 26, 2012 at 3:19 PM, Tillmann Rendel
> < [hidden email]> wrote:
>> All fine so far. Now, consider the following additional requirement: "If
>> the
>> commandline flag multiply is set, the function amount computes the
>> product instead of the sum."
>>
>> How would you implement this requirement in Haskell without changing the
>> line "amount (Leaf x) = x"?
>
> One option is to encode the desired behavior at the type level. By
> extended the data type slightly and adding a Functor instance,
> selecting between a product and a sum can be done using their Monoid
> newtypes: ...
Better yet, use foldMap:
> import Data.Monoid
> import Data.Foldable
> import System.Environment
> data Tree a = Leaf a  Branch (Tree a) (Tree a)
> instance Functor Tree where
> f `fmap` Leaf x = Leaf (f x)
> f `fmap` Branch x y = Branch (fmap f x) (fmap f y)
> instance Foldable Tree where
> foldMap f (Leaf x) = f x
> foldMap f (Branch s t) = foldMap f s <> foldMap f t
> main :: IO ()
> main = do
> args < getArgs
> let val :: Tree Int
> val = Branch (Leaf 8) (Leaf 18)
> let getResult :: Tree Int > Int
> getResult = case args of
> ["multiply"] > getProduct . foldMap Product
> _ > getSum . foldMap Sum
> print . getResult $ val
Yet better yet:
> {# LANGUAGE DeriveFunctor, DeriveFoldable #}
> import Data.Monoid;
> import Data.Foldable;
> import System.Environment
> data Tree a = Leaf a  Branch (Tree a) (Tree a)
> deriving (Functor, Foldable);
> ...
(^_^)

Strake
_______________________________________________
HaskellCafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskellcafe


To be fair, while it's great that Functor et al. are available to
help solve problems like that with a Tree data structure, in the
present context it mostly shows that a trivial example was used
to illustrate the problem. Unless I'm missing how this generic
fold functionality solves the more general problem.
Quoth Alberto G. Corona,
> ... There is no such problem in imperative languages, which work
> ever in an hardwired IO monad.
Or to look at it from the other direction, the problem with Haskell
is that it allows the programmer to write nonIO functions. To the
extent that's a real problem, the solution would obviously be to
exercise some restraint with the pure code and write more in the
IO monad. If you will humor me, we understand that this code is
equally satisfactory from a mathematical perspective and there's
no crime in it. But does it help with the `flags problem?'
Suppose that functions f and g both have IO types; f calls g,
and g has optional behavior depending on some IO value computed
previously, the flag. The way I understand it, I can accomplish
this without passing the flag around: with an IORef.
What's less clear to me is whether Haskell really supports the module
level accessible IORef value I need. Also known as "top level mutable
state." Is the NOINLINE pragma I've been using with GHC, really a
sound and reliable practice that we're reasonably confident will be
supported by other compilers?
It feels to me like I'm pulling a weird trick, to do something that's
trivial in other programming languages. Maybe that's part of the
problem, that imperative programming receives something a little short
of full support in Haskell, inasmuch as basic features like top level
mutable state require relatively arcane incantations.
Donn
_______________________________________________
HaskellCafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskellcafe


2012/6/27 Tillmann Rendel < [hidden email]>:
> MightyByte wrote:
>>
>> Of course every line of your program that uses a Foo will change if you
>> switch
>> to IO Foo instead.
>
>
> But we often have to also change lines that don't use Foo at all. For
> example, here is the type of binary trees of integers:
>
> data Tree = Leaf Integer  Branch (Tree Integer) (Tree Integer)
>
> A function to add up all integers in a tree:
>
> amount:: Tree > Integer
> amount (Leaf x) = x
> amount (Branch t1 t2) = amountt1 + amountt2
>
> All fine so far. Now, consider the following additional requirement: "If the
> commandline flag multiply is set, the function amount computes the
> product instead of the sum."
>
> In a language with implicit side effects, it is easy to implement this. We
> just change the third line of the amount function to check whether to call
> (+) or (*). In particular, we would not touch the other two lines.
>
> How would you implement this requirement in Haskell without changing the
> line "amount (Leaf x) = x"?
I may be missing the point here, but having worked on large code bases
with a wide variety contributors before, I find it very advantageous
that programmers are prevented from writing an amount function whose
behaviour depends on command line arguments without at least an
indication in the type. The fact that the function can not perform
stuff like that is precisely the guarantee that the Haskell type gives
me...
Dominique
_______________________________________________
HaskellCafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskellcafe


Any idea whether Martin Odersky has read this discussion? Thanks and regards, Damodar Kulkarni On Fri, Jun 29, 2012 at 12:23 AM, Dominique Devriese <[hidden email]> wrote:
2012/6/27 Tillmann Rendel <[hidden email]>:
> MightyByte wrote:
>>
>> Of course every line of your program that uses a Foo will change if you
>> switch
>> to IO Foo instead.
>
>
> But we often have to also change lines that don't use Foo at all. For
> example, here is the type of binary trees of integers:
>
> data Tree = Leaf Integer  Branch (Tree Integer) (Tree Integer)
>
> A function to add up all integers in a tree:
>
> amount:: Tree > Integer
> amount (Leaf x) = x
> amount (Branch t1 t2) = amountt1 + amountt2
>
> All fine so far. Now, consider the following additional requirement: "If the
> commandline flag multiply is set, the function amount computes the
> product instead of the sum."
>
> In a language with implicit side effects, it is easy to implement this. We
> just change the third line of the amount function to check whether to call
> (+) or (*). In particular, we would not touch the other two lines.
>
> How would you implement this requirement in Haskell without changing the
> line "amount (Leaf x) = x"?
I may be missing the point here, but having worked on large code bases
with a wide variety contributors before, I find it very advantageous
that programmers are prevented from writing an amount function whose
behaviour depends on command line arguments without at least an
indication in the type. The fact that the function can not perform
stuff like that is precisely the guarantee that the Haskell type gives
me...
Dominique
_______________________________________________
HaskellCafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskellcafe


In reply to this post by Dominique Devriese2
On Thu, Jun 28, 2012 at 2:53 PM, Dominique Devriese
< [hidden email]> wrote:
> 2012/6/27 Tillmann Rendel < [hidden email]>:
>> How would you implement this requirement in Haskell without changing the
>> line "amount (Leaf x) = x"?
>
> I may be missing the point here, but having worked on large code bases
> with a wide variety contributors before, I find it very advantageous
> that programmers are prevented from writing an amount function whose
> behaviour depends on command line arguments without at least an
> indication in the type. The fact that the function can not perform
> stuff like that is precisely the guarantee that the Haskell type gives
> me...
I don't think there's an answer that's uniformly right; it depends on
whether you think of the input to the program, e.g. the environment,
commandline arguments, etc. as 'constant' and in some sense, pure.
The latter are constant in the sense that they never change, but they
are not fixed at compiletime. Other languages effectively treat them
as pure (by passing them directly to main), whereas Haskell chooses
not to, which is probably the reason why getArgs has IO in its type
(something that seems unintuitive at first.)
That precedent supports the view that e.g. a commandline flag
shouldn't affect behavior without the type reflecting it, e.g. by
doing IO, but the de facto use of the unsafe IO trick means not
everyone agrees.
_______________________________________________
HaskellCafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskellcafe


> That precedent supports the view that e.g. a commandline flag
> shouldn't affect behavior without the type reflecting it, e.g. by
> doing IO, but the de facto use of the unsafe IO trick means not
> everyone agrees.
For those interested, here's [1] a case where treating command line
arguments as top level constants went wrong.
Look specifically at the section named "Crime Doesn't Pay".
Best,
Facundo
[1] http://www.aosabook.org/en/ghc.html> Date: Tue, 3 Jul 2012 17:49:48 0400
> From: Alvaro Gutierrez < [hidden email]>
> Subject: Re: [Haskellcafe] Martin Odersky on "What's wrong with
> Monads"
> To: Dominique Devriese < [hidden email]>
> Cc: [hidden email]
> MessageID:
> < [hidden email]>
> ContentType: text/plain; charset=ISO88591
>
> On Thu, Jun 28, 2012 at 2:53 PM, Dominique Devriese
> < [hidden email]> wrote:
>> 2012/6/27 Tillmann Rendel < [hidden email]>:
>>> How would you implement this requirement in Haskell without changing the
>>> line "amount (Leaf x) = x"?
>>
>> I may be missing the point here, but having worked on large code bases
>> with a wide variety contributors before, I find it very advantageous
>> that programmers are prevented from writing an amount function whose
>> behaviour depends on command line arguments without at least an
>> indication in the type. The fact that the function can not perform
>> stuff like that is precisely the guarantee that the Haskell type gives
>> me...
>
> I don't think there's an answer that's uniformly right; it depends on
> whether you think of the input to the program, e.g. the environment,
> commandline arguments, etc. as 'constant' and in some sense, pure.
> The latter are constant in the sense that they never change, but they
> are not fixed at compiletime. Other languages effectively treat them
> as pure (by passing them directly to main), whereas Haskell chooses
> not to, which is probably the reason why getArgs has IO in its type
> (something that seems unintuitive at first.)
>
> That precedent supports the view that e.g. a commandline flag
> shouldn't affect behavior without the type reflecting it, e.g. by
> doing IO, but the de facto use of the unsafe IO trick means not
> everyone agrees.
>
_______________________________________________
HaskellCafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskellcafe


In reply to this post by Dominique Devriese2
In practice, the amount of time you have to spend testing each function, to make sure its IO doesn't trip up in some corner case, is usually greater than the amount of time a rewriteforIO would take.
Tom
On Jun 28, 2012 2:54 PM, "Dominique Devriese" < [hidden email]> wrote:
2012/6/27 Tillmann Rendel <[hidden email]>:
> MightyByte wrote:
>>
>> Of course every line of your program that uses a Foo will change if you
>> switch
>> to IO Foo instead.
>
>
> But we often have to also change lines that don't use Foo at all. For
> example, here is the type of binary trees of integers:
>
> data Tree = Leaf Integer  Branch (Tree Integer) (Tree Integer)
>
> A function to add up all integers in a tree:
>
> amount:: Tree > Integer
> amount (Leaf x) = x
> amount (Branch t1 t2) = amountt1 + amountt2
>
> All fine so far. Now, consider the following additional requirement: "If the
> commandline flag multiply is set, the function amount computes the
> product instead of the sum."
>
> In a language with implicit side effects, it is easy to implement this. We
> just change the third line of the amount function to check whether to call
> (+) or (*). In particular, we would not touch the other two lines.
>
> How would you implement this requirement in Haskell without changing the
> line "amount (Leaf x) = x"?
I may be missing the point here, but having worked on large code bases
with a wide variety contributors before, I find it very advantageous
that programmers are prevented from writing an amount function whose
behaviour depends on command line arguments without at least an
indication in the type. The fact that the function can not perform
stuff like that is precisely the guarantee that the Haskell type gives
me...
Dominique
_______________________________________________
HaskellCafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskellcafe
_______________________________________________
HaskellCafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskellcafe

12
