Bool as type class to serve EDSLs.

Hello, While playing with embedded domain specific languages in Haskell I discovered the Num type class is a really neat tool. Take this simple example embedded language that can embed primitives from the output language and can do function application.
data Expr :: * -> * where Prim :: String -> Expr a App :: Expr (a -> b) -> Expr a -> Expr b
Take these two dummy types to represent things in the output language.
data MyNum data MyBool
Now it is very easy to create an Num instance for this language:
primPlus :: Expr (MyNum -> MyNum -> MyNum) primPlus = Prim "prim+"
instance Num (Epxr MyNum) where a + b = primPlus `App` a `App` b fromInteger = Prim . show ...
Which allows you to create very beautiful expression for your language embedded inside Haskell. The Haskell expression `10 * 5 + 2' produces a nice and well typed expression in your embedded domain. But unfortunately, not everyone in the Prelude is as tolerant as the Num instance. Take the Eq and the Ord type classes for example, they require you to deliver real Haskell `Bool's. This makes it impossible make your DSL an instance of these two, because there are no `Bool's only `Expr Bool's. Which brings me to the point that, for the sake of embedding other languages, Haskell's Prelude (or an alternative) can greatly benefit from (at least) a Boolean type class like this: class Boolean a where ifthenelse :: a -> b -> b -> b -- Not sure about this representation. ... And one instance:
instance Boolean (Expr MyBool) where ifthenelse c a b = Prim "if-then-else" `App` c `App` a `App` b
Now we can change (for example) the Eq type class to this:
class Eq a where (==) :: Boolean b => a -> a -> b (/=) :: Boolean b => a -> a -> b
For which we can give an implementation for our domain:
primEq :: Epxr (a -> a -> MyBool) primEq = Prim "=="
instance Eq (Expr a) where a == b = primEq `App` a `App` b
And now we get all functionality from the Prelude that is based on Eq (like not, &&, ||, etc) for free in our domain specific language! Off course there are many, many more examples of things from the standard libraries that can be generalised in order to serve reuse in EDSLs. Anyone already working on such a generalized Prelude? I can imagine much more domains can benefit from this than my example above. Any interesting thoughts or pointers related to this subject? Gr, -- Sebastiaan Visser

+1. I agree completely, I've missed this often for exactly the same reasons. Edsko

And I would certainly celebrate when "if b then x else y" expression becomes polymorphic in "b". Edsko de Vries wrote on 27.05.2009 17:33:
+1. I agree completely, I've missed this often for exactly the same reasons.
Edsko
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

You are absolutely right about the tantalising opportunity. I know that Lennart has thought quite a bit about this very point when designing his Paradise system. Likewise Conal for Pan. One difficulty is, I think, that it's easy to get ambiguity. Eg ifthenelse (a > b) e1 e2 The (a>b) produces a boolean-thing, and ifthenelse consumes it; but which type of boolean? The Expr type? Real Bools? Or what? If there was a nice design, then GHC's existing -fno-implicit-prelude flag could be extended (again) to desugar if-then-else to the new thing. But the design is unclear, to me anyway. Simon | -----Original Message----- | From: haskell-cafe-bounces@haskell.org [mailto:haskell-cafe-bounces@haskell.org] On | Behalf Of Sebastiaan Visser | Sent: 27 May 2009 13:32 | To: Haskell Cafe | Subject: [Haskell-cafe] Bool as type class to serve EDSLs. | | Hello, | | While playing with embedded domain specific languages in Haskell I | discovered the Num type class is a really neat tool. Take this simple | example embedded language that can embed primitives from the output | language and can do function application. | | >data Expr :: * -> * where | > Prim :: String -> Expr a | > App :: Expr (a -> b) -> Expr a -> Expr b | | Take these two dummy types to represent things in the output language. | | >data MyNum | >data MyBool | | Now it is very easy to create an Num instance for this language: | | >primPlus :: Expr (MyNum -> MyNum -> MyNum) | >primPlus = Prim "prim+" | | >instance Num (Epxr MyNum) where | > a + b = primPlus `App` a `App` b | > fromInteger = Prim . show | > ... | | Which allows you to create very beautiful expression for your language | embedded inside Haskell. The Haskell expression `10 * 5 + 2' produces | a nice and well typed expression in your embedded domain. | | But unfortunately, not everyone in the Prelude is as tolerant as the | Num instance. Take the Eq and the Ord type classes for example, they | require you to deliver real Haskell `Bool's. This makes it impossible | make your DSL an instance of these two, because there are no `Bool's | only `Expr Bool's. | | Which brings me to the point that, for the sake of embedding other | languages, Haskell's Prelude (or an alternative) can greatly benefit | from (at least) a Boolean type class like this: | | class Boolean a where | ifthenelse :: a -> b -> b -> b -- Not sure about this | representation. | ... | | And one instance: | | >instance Boolean (Expr MyBool) where | > ifthenelse c a b = Prim "if-then-else" `App` c `App` a `App` b | | Now we can change (for example) the Eq type class to this: | | >class Eq a where | > (==) :: Boolean b => a -> a -> b | > (/=) :: Boolean b => a -> a -> b | | For which we can give an implementation for our domain: | | >primEq :: Epxr (a -> a -> MyBool) | >primEq = Prim "==" | | >instance Eq (Expr a) where | > a == b = primEq `App` a `App` b | | And now we get all functionality from the Prelude that is based on Eq | (like not, &&, ||, etc) for free in our domain specific language! Off | course there are many, many more examples of things from the standard | libraries that can be generalised in order to serve reuse in EDSLs. | | Anyone already working on such a generalized Prelude? I can imagine | much more domains can benefit from this than my example above. Any | interesting thoughts or pointers related to this subject? | | Gr, | | -- | Sebastiaan Visser | | _______________________________________________ | Haskell-Cafe mailing list | Haskell-Cafe@haskell.org | http://www.haskell.org/mailman/listinfo/haskell-cafe

There are multiple possible classes that you might want under different circumstances (I think the most interesting issue is whether the class (==), (>) etc is in has a fundep from the type of the thing being compared to the type of the boolean), but if NoImplicitPrelude (or some other extension) just desugars if-then-else into ifthenelse (with a default implementation of ifthenelse somewhere) I think that would be enough. Of course once you've got ifthenelse you find yourself wanting explicit desugaring of pattern matching (could view patterns help here?), recursion (into an explicit use of fix), etc... Cheers, Ganesh Simon Peyton-Jones wrote:
You are absolutely right about the tantalising opportunity. I know that Lennart has thought quite a bit about this very point when designing his Paradise system. Likewise Conal for Pan.
One difficulty is, I think, that it's easy to get ambiguity. Eg ifthenelse (a > b) e1 e2 The (a>b) produces a boolean-thing, and ifthenelse consumes it; but which type of boolean? The Expr type? Real Bools? Or what?
If there was a nice design, then GHC's existing -fno-implicit-prelude flag could be extended (again) to desugar if-then-else to the new thing. But the design is unclear, to me anyway.
Simon
-----Original Message----- From: haskell-cafe-bounces@haskell.org [mailto:haskell-cafe-bounces@haskell.org] On Behalf Of Sebastiaan Visser Sent: 27 May 2009 13:32 To: Haskell Cafe Subject: [Haskell-cafe] Bool as type class to serve EDSLs.
Hello,
While playing with embedded domain specific languages in Haskell I discovered the Num type class is a really neat tool. Take this simple example embedded language that can embed primitives from the output language and can do function application.
data Expr :: * -> * where Prim :: String -> Expr a App :: Expr (a -> b) -> Expr a -> Expr b
Take these two dummy types to represent things in the output language.
data MyNum data MyBool
Now it is very easy to create an Num instance for this language:
primPlus :: Expr (MyNum -> MyNum -> MyNum) >primPlus = Prim "prim+"
instance Num (Epxr MyNum) where a + b = primPlus `App` a `App` b fromInteger = Prim . show ...
Which allows you to create very beautiful expression for your language embedded inside Haskell. The Haskell expression `10 * 5 + 2' produces a nice and well typed expression in your embedded domain.
But unfortunately, not everyone in the Prelude is as tolerant as the Num instance. Take the Eq and the Ord type classes for example, they require you to deliver real Haskell `Bool's. This makes it impossible make your DSL an instance of these two, because there are no `Bool's only `Expr Bool's.
Which brings me to the point that, for the sake of embedding other languages, Haskell's Prelude (or an alternative) can greatly benefit from (at least) a Boolean type class like this:
class Boolean a where ifthenelse :: a -> b -> b -> b -- Not sure about this representation. ...
And one instance:
instance Boolean (Expr MyBool) where > ifthenelse c a b = Prim "if-then-else" `App` c `App` a `App` b
Now we can change (for example) the Eq type class to this:
class Eq a where (==) :: Boolean b => a -> a -> b (/=) :: Boolean b => a -> a -> b
For which we can give an implementation for our domain:
primEq :: Epxr (a -> a -> MyBool) primEq = Prim "=="
instance Eq (Expr a) where a == b = primEq `App` a `App` b
And now we get all functionality from the Prelude that is based on Eq (like not, &&, ||, etc) for free in our domain specific language! Off course there are many, many more examples of things from the standard libraries that can be generalised in order to serve reuse in EDSLs.
Anyone already working on such a generalized Prelude? I can imagine much more domains can benefit from this than my example above. Any interesting thoughts or pointers related to this subject?
Gr,
-- Sebastiaan Visser
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
=============================================================================== Please access the attached hyperlink for an important electronic communications disclaimer: http://www.credit-suisse.com/legal/en/disclaimer_email_ib.html ===============================================================================

Of course once you've got ifthenelse you find yourself wanting explicit desugaring of pattern matching (could view patterns help here?),
Could you be more specific about what you want there, perhaps with a small example? I recognize the other problems from my own forays into EDSLs, but I'm not sure I recognize this one. If you want to reuse the existing 'lhs=rhs' syntax for patterns specific to your EDSL, both QuasiQuotes and ViewPatterns might help, if you want to be able to compose patterns beyond the limitations of that syntax, one of the proposals and libraries for first-class patterns might help, adding functionality at the expense of more complex syntax.
recursion (into an explicit use of fix), etc...
Yes, in principle (you're thinking of sharing, and of lifting pure code?). In practice, too much machinery is attached to the existing 'let' to make that likely. But this reminds me of another closely related issue: GHC offers a lot of help in moving stuff from compiler-baked-in to library-provided, but almost none of the mechanisms works at the level of syntax/AST (where most other languages do their meta-programming/language extension support). RULES and compiler plugins work on core, where it is too late to do EDSL-specific source-level rewrites, TH requires quoted things to parse and type-check in the un-extended language, making it less useful for EDSL-specific language extensions. For instance, think of the arrows syntax: there doesn't seem to be any way that this could have been defined in a library, so it had to be baked into GHC? QuasiQuotes seem to be the only feature that gives source-level control, and they suffer from the lack of easily available parsers (eg, if my EDSL requires an extension of some Haskell construct, I'd like to be able to reuse the Haskell parsers for the baseline). There is a package on hackage targetting that issue (haskell-src-meta), but it relies on a second frontend (haskell-src-ext), and only works with a single GHC version. Claus

Here's what I usually use. As Simon points out, ambiguity is lurking
as soon as you use conditional. You can avoid it a fundep, but that's
not necessarily what you want either.
-- | Generalization of the 'Bool' type. Used by the generalized 'Eq' and 'Ord'.
class Boolean bool where
(&&) :: bool -> bool -> bool -- ^Logical conjunction.
(||) :: bool -> bool -> bool -- ^Logical disjunction.
not :: bool -> bool -- ^Locical negation.
false :: bool -- ^Truth.
true :: bool -- ^Falsity.
fromBool :: Bool -> bool -- ^Convert a 'Bool' to the
generalized Boolean type.
fromBool b = if b then true else false
-- | Generalization of the @if@ construct.
class (Boolean bool) => Conditional bool a where
conditional :: bool -> a -> a -> a -- ^Pick the first argument if
the 'Boolean' value is true, otherwise the second argument.
class (Boolean bool) => Eq a bool {- x | a -> bool -} where
(==) :: a -> a -> bool
(/=) :: a -> a -> bool
x /= y = not (x == y)
x == y = not (x /= y)
On Thu, May 28, 2009 at 8:14 AM, Simon Peyton-Jones
You are absolutely right about the tantalising opportunity. I know that Lennart has thought quite a bit about this very point when designing his Paradise system. Likewise Conal for Pan.
One difficulty is, I think, that it's easy to get ambiguity. Eg ifthenelse (a > b) e1 e2 The (a>b) produces a boolean-thing, and ifthenelse consumes it; but which type of boolean? The Expr type? Real Bools? Or what?
If there was a nice design, then GHC's existing -fno-implicit-prelude flag could be extended (again) to desugar if-then-else to the new thing. But the design is unclear, to me anyway.
Simon
| -----Original Message----- | From: haskell-cafe-bounces@haskell.org [mailto:haskell-cafe-bounces@haskell.org] On | Behalf Of Sebastiaan Visser | Sent: 27 May 2009 13:32 | To: Haskell Cafe | Subject: [Haskell-cafe] Bool as type class to serve EDSLs. | | Hello, | | While playing with embedded domain specific languages in Haskell I | discovered the Num type class is a really neat tool. Take this simple | example embedded language that can embed primitives from the output | language and can do function application. | | >data Expr :: * -> * where | > Prim :: String -> Expr a | > App :: Expr (a -> b) -> Expr a -> Expr b | | Take these two dummy types to represent things in the output language. | | >data MyNum | >data MyBool | | Now it is very easy to create an Num instance for this language: | | >primPlus :: Expr (MyNum -> MyNum -> MyNum) | >primPlus = Prim "prim+" | | >instance Num (Epxr MyNum) where | > a + b = primPlus `App` a `App` b | > fromInteger = Prim . show | > ... | | Which allows you to create very beautiful expression for your language | embedded inside Haskell. The Haskell expression `10 * 5 + 2' produces | a nice and well typed expression in your embedded domain. | | But unfortunately, not everyone in the Prelude is as tolerant as the | Num instance. Take the Eq and the Ord type classes for example, they | require you to deliver real Haskell `Bool's. This makes it impossible | make your DSL an instance of these two, because there are no `Bool's | only `Expr Bool's. | | Which brings me to the point that, for the sake of embedding other | languages, Haskell's Prelude (or an alternative) can greatly benefit | from (at least) a Boolean type class like this: | | class Boolean a where | ifthenelse :: a -> b -> b -> b -- Not sure about this | representation. | ... | | And one instance: | | >instance Boolean (Expr MyBool) where | > ifthenelse c a b = Prim "if-then-else" `App` c `App` a `App` b | | Now we can change (for example) the Eq type class to this: | | >class Eq a where | > (==) :: Boolean b => a -> a -> b | > (/=) :: Boolean b => a -> a -> b | | For which we can give an implementation for our domain: | | >primEq :: Epxr (a -> a -> MyBool) | >primEq = Prim "==" | | >instance Eq (Expr a) where | > a == b = primEq `App` a `App` b | | And now we get all functionality from the Prelude that is based on Eq | (like not, &&, ||, etc) for free in our domain specific language! Off | course there are many, many more examples of things from the standard | libraries that can be generalised in order to serve reuse in EDSLs. | | Anyone already working on such a generalized Prelude? I can imagine | much more domains can benefit from this than my example above. Any | interesting thoughts or pointers related to this subject? | | Gr, | | -- | Sebastiaan Visser | | _______________________________________________ | Haskell-Cafe mailing list | Haskell-Cafe@haskell.org | http://www.haskell.org/mailman/listinfo/haskell-cafe
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Hello Lennart, Thursday, May 28, 2009, 11:57:09 AM, you wrote:
-- | Generalization of the 'Bool' type. Used by the generalized 'Eq' and 'Ord'. class Boolean bool where (&&) :: bool -> bool -> bool -- ^Logical conjunction. (||) :: bool -> bool -> bool -- ^Logical disjunction.
i use another approach which imho is somewhat closer to interpretation of logical operations in dynamic languages (lua, ruby, perl): a ||| b | isDefaultValue a = b | otherwise = a a &&& b | isDefaultValue a = defaultValue | otherwise = b -- Class of types having default value: class Defaults a where defaultValue :: a instance Defaults () where defaultValue = () instance Defaults Bool where defaultValue = False instance Defaults [a] where defaultValue = [] instance Defaults (a->a) where defaultValue = id instance Defaults (Maybe a) where defaultValue = Nothing instance Defaults (a->IO a) where defaultValue = return instance Defaults a => Defaults (IO a) where defaultValue = return defaultValue instance Defaults Int where defaultValue = 0 instance Defaults Integer where defaultValue = 0 instance Defaults Double where defaultValue = 0 -- Class of types that can be tested for default value: class TestDefaultValue a where isDefaultValue :: a -> Bool instance TestDefaultValue Bool where isDefaultValue = not instance TestDefaultValue [a] where isDefaultValue = null instance TestDefaultValue Int where isDefaultValue = (==0) instance TestDefaultValue Integer where isDefaultValue = (==0) instance TestDefaultValue Double where isDefaultValue = (==0) usage examples: return$ (isDir &&& addTrailingPathSeparator) filespec openWebsite$ (isWindows &&& windosifyPath) file let options = (compressionEnabled &&& cvt "-m" compressionMethod')++ (encryptionEnabled &&& cvt "-ae=" encryptionMethod')++encryptionOptions++ (protectionEnabled &&& cvt "-rr" protectionMethod') let another_msg = ciphers ||| "not encrypted" let msg = ftLocked footer &&& "yes" ||| "no" -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com

Excerpts from Bulat Ziganshin's message of Thu May 28 15:07:02 +0200 2009:
Hello Lennart,
Thursday, May 28, 2009, 11:57:09 AM, you wrote:
-- | Generalization of the 'Bool' type. Used by the generalized 'Eq' and 'Ord'. class Boolean bool where (&&) :: bool -> bool -> bool -- ^Logical conjunction. (||) :: bool -> bool -> bool -- ^Logical disjunction.
i use another approach which imho is somewhat closer to interpretation of logical operations in dynamic languages (lua, ruby, perl):
I tend to prefer Monoid: (|||) :: (Monoid a, Eq a) => a -> a -> a a ||| b | a == mempty = b | otherwise = a (&&&) :: (Monoid a, Eq a, Monoid b) => a -> b -> b a &&& b | a == mempty = mempty | otherwise = b In particular I also like this one (however I would like another name): mapNonEmpty :: (Eq a, Monoid a, Monoid b) => (a -> b) -> a -> b mapNonEmpty f x | x == mempty = mempty | otherwise = f x Best regards, -- Nicolas Pouillard http://nicolaspouillard.fr

On Thu, 28 May 2009, Bulat Ziganshin wrote:
i use another approach which imho is somewhat closer to interpretation of logical operations in dynamic languages (lua, ruby, perl):
a ||| b | isDefaultValue a = b | otherwise = a
a &&& b | isDefaultValue a = defaultValue | otherwise = b
-- Class of types having default value: class Defaults a where defaultValue :: a instance Defaults () where defaultValue = () instance Defaults Bool where defaultValue = False instance Defaults [a] where defaultValue = []
The absence of such interpretations and thus the increased type safety was one of the major the reasons for me to move from scripting languages to Haskell.

On Jun 1, 2009, at 12:17 AM, Henning Thielemann wrote:
On Thu, 28 May 2009, Bulat Ziganshin wrote:
i use another approach which imho is somewhat closer to interpretation of logical operations in dynamic languages (lua, ruby, perl): [...]
The absence of such interpretations and thus the increased type safety was one of the major the reasons for me to move from scripting languages to Haskell.
Do you argue that overloading logical operations like this in Haskell sacrifices type safety? Could programs "go wrong" [1] that use such abstractions? [1]: Robin Milner. A theory of type polymorphism in programming. J. Comput. Syst. Sci., 17:348–375, 1978. -- Underestimating the novelty of the future is a time-honored tradition. (D.G.)

On Mon, Jun 1, 2009 at 3:06 AM, Sebastian Fischer < sebf@informatik.uni-kiel.de> wrote:
On Jun 1, 2009, at 12:17 AM, Henning Thielemann wrote:
On Thu, 28 May 2009, Bulat Ziganshin wrote:
i use another approach which imho is somewhat closer to interpretation
of logical operations in dynamic languages (lua, ruby, perl): [...]
The absence of such interpretations and thus the increased type safety was one of the major the reasons for me to move from scripting languages to Haskell.
Do you argue that overloading logical operations like this in Haskell sacrifices type safety? Could programs "go wrong" [1] that use such abstractions?
If I understand your point correctly, you are suggesting that such programs are still type safe. I agree with the claim that such features are detrimental in practice though. Instead of lumping it with type safety, then what do we call it? I think I've heard of languages that do such conversions as "weakly" typed. Really the issue is with implicit conversions, right? Jason

Do you argue that overloading logical operations like this in Haskell sacrifices type safety? Could programs "go wrong" [1] that use such abstractions?
If I understand your point correctly, you are suggesting that such programs are still type safe. I agree with the claim that such features are detrimental in practice though. Instead of lumping it with type safety, then what do we call it? I think I've heard of languages that do such conversions as "weakly" typed. Really the issue is with implicit conversions, right?
Isn't it merely a matter of balance? In order for typed programs not to go "wrong", one has to define "right" and "wrong", and devise a type system that rules out anything that might go "wrong", usually at the expense of some programs that might go "right". Advanced type system features like overloading take that unused space and devise ways to redirect code that would go "wrong" (in simpler systems) to go "right" in useful new ways (eg: adding two functions or matrices or .. does not have to be "wrong", there are interpretations in which all of these make perfect sense, and Haskell can express many of them). What is happening then is that more and more of the previously "wrong" space is filled up with meaningful ways of going "right", until nearly every syntactically valid program goes somewhere. That can make for an extremely expressive and powerful language, but it renders the naive notion of going "wrong" or "right" rather meaningless: "wrong" just means we haven't figured out a meaningful way to interpret it, and going "right" can easily be a far cry from where you wanted it to go. Claus PS. this problem can be made worse if the implicit conversions aren't consistent, if small "twitches" in source code can lead to grossly different behaviour. There is a fine line between advanced and uncontrollable, and opinions on what side of the line any given definition is on can differ.

Do you argue that overloading logical operations like this in Haskell sacrifices type safety? Could programs "go wrong" [1] that use such abstractions? If I understand your point correctly, you are suggesting that such programs are still type safe.
My asking was really meant as a question to find out what Henning meant when he talked about type safety.
I agree with the claim that such features are detrimental in practice though.
I also feel uncomfortable about such features, but the problem seems to be different from type safety. Maybe it is more about predictability. For example, if '1 + 23 = 24' and '1 + "23" = "123"' this can lead to confusion although using overloading this could be done in Haskell. That the compiler is able to figure out a correct instantiation of an overloaded operation does not mean that it is easy for the programmer too. And if it is not, programs are hard to understand.
Instead of lumping it with type safety, then what do we call it? I think I've heard of languages that do such conversions as "weakly" typed. Really the issue is with implicit conversions, right?
Isn't it merely a matter of balance? In order for typed programs not to go "wrong", one has to define "right" and "wrong", and devise a type system that rules out anything that might go "wrong", usually at the expense of some programs that might go "right".
I had in mind "causes a run-time error" as definition of "goes wrong". But this simple view may well be inaccurate.
Advanced type system features like overloading take that unused space and devise ways to redirect code that would go "wrong" (in simpler systems) to go "right" in useful new ways (eg: adding two functions or matrices or .. does not have to be "wrong", there are interpretations in which all of these make perfect sense, and Haskell can express many of them).
What is happening then is that more and more of the previously "wrong" space is filled up with meaningful ways of going "right", until nearly every syntactically valid program goes somewhere. That can make for an extremely expressive and powerful language, but it renders the naive notion of going "wrong" or "right" rather meaningless: "wrong" just means we haven't figured out a meaningful way to interpret it, and going "right" can easily be a far cry from where you wanted it to go.
I (think I) agree with you. Overloading could give a meaning to almost everything. Not necessarily a sensible one, and judgements about what is sensible seem to differ among different people. Regardless of whether a specific overloading is *sensible*, wanting it to be *predictable* seems like a reasonable requirement which may be easier to agree on. Cheers, Sebastian -- Underestimating the novelty of the future is a time-honored tradition. (D.G.)

Claus Reinke wrote:
Do you argue that overloading logical operations like this in Haskell sacrifices type safety? Could programs "go wrong" [1] that use such abstractions?
If I understand your point correctly, you are suggesting that such programs are still type safe. I agree with the claim that such features are detrimental in practice though. Instead of lumping it with type safety, then what do we call it? I think I've heard of languages that do such conversions as "weakly" typed. Really the issue is with implicit conversions, right?
Isn't it merely a matter of balance?
You are completely right. I have to rephrase: The concrete example of interpreting lists as booleans leads to too weak typing for my taste. Let me give Python as an example: It has no static check whether a sub-routine contains a 'return' statement. If it calls 'return', you might call it a function, if it does not call 'return', you might call it a procedure. Whether 'return' is called may vary at run-time, thus a sub-routine can be both function and procedure. However, if the sub-routine does not call 'return' it implicitly calls 'return None' when leaving the scope of the sub-routine. 'None' is a value of every type, just like bottom in Haskell. But in contrast to Haskell 'None' is a well-defined value. As far as I remember, it is considered 'false' in logical expressions. (PHP is even more extreme in interpreting all kinds of values as booleans.) Now, whenever you forget to call 'return' the resulting 'None' goes unnoticed through your program until at a very unrelated place an error like "you tried to access the 5-th element of the list None, which does not exist" pops up. Sure we can implement this behaviour in Haskell, too, e.g. using the Maybe type - but should we do it? I prefer an interpreter which refuses to start the program with the message: 'you forgot a return'. -- Mit freundlichen Gruessen Henning Thielemann Viele Gruesse Henning Martin-Luther-Universitaet Halle-Wittenberg, Institut fuer Informatik Tel. +49 - 345 - 55 24773 Fax +49 - 345 - 55 27333
participants (13)
-
Bulat Ziganshin
-
Claus Reinke
-
Edsko de Vries
-
Henning Thielemann
-
Jason Dagit
-
Jason Dusek
-
Lennart Augustsson
-
Miguel Mitrofanov
-
Nicolas Pouillard
-
Sebastiaan Visser
-
Sebastian Fischer
-
Simon Peyton-Jones
-
Sittampalam, Ganesh