News aggregator

Yesod Web Framework: Clarification of previous blog post

Planet Haskell - Wed, 09/10/2014 - 6:00pm

I've heard that my previous blog post has caused a bit of confusion, as sarcasm doesn't really come across in text very well. So let me elaborate (and of course, in the process, kill the joke):

Some years back, Erik found a case that was quite difficult to implement using enumerator. After we cracked our heads on it for long enough, some of us (I don't actually remember who was involved) decided to work on a new streaming library. That library ended up being called conduit (thanks to Yitz for the naming idea). It turns out that most people are unaware of that history, so when at ICFP, I casually mentioned that Erik was the cause of conduit coming into existence, some people were surprised. Erik jokingly chastised me for not giving him enough credit. In response, I decided to write an over-the-top post giving Erik all credit for conduit. I say over the top, since I made it seem like there was some large amount of blame being heaped on as well.

So to be completely clear:

  • Erik and I are good friends, and this was just a bit of an inside joke turned public.
  • No one has said anything offensive to me at all about conduit. There are obviously differing opinions out there about the best library for a job, but there's nothing offensive about it, just healthy discussion around a complicated topic. My purpose in making a big deal about it was not to express frustration at anyone attacking me, but rather to just play up the joke a bit more.

My apologies to anyone who was confused, upset, or worried by the previous post, it was completely unintentional.

Categories: Offsite Blogs

Categorical description for vector-space instance of AdditiveGroup (Maybe a)

haskell-cafe - Wed, 09/10/2014 - 4:13pm
Hi Haskell Cafe, In Vector-space-0.8.7, there is the cited inconsistency of the definition of AdditiveGroup (Maybe a). I've posted the source, including comment, below for reference. Following the logic of the counterexample and Conal's (and or Andy Gill's) comment, the problem hinges on the equality, Nothing = Just (zeroV :: a). I'm curious about the catigorical description of this situation. Does this mean that the category of Additive Groups and Maybe Additive Groups are equivalent as categories? I'm not proposing that this is somehow a resolution to vector-space, but rather trying to gain some insight into equivalence, naturalitity, adjunction, etc. My thinking as to why equivalence is that if we have the instance below defined using: zeroV = Just zeroV and making appropriate changes following that new decision. Nothing ^+^ Nothing = zeroV a ^+^ Nothing = a Nothing ^+^ b = b negateV Nothing = zeroV negateV a = fmap negateV then we pretty much defer the group structure of (Maybe a) to be b
Categories: Offsite Discussion

LinkedIn job ad link for openings for severalenthusiastic great Haskell developers (geoloc. globally) atSwedish spin-off Functor Group with subsidiaries + threeScala developer (geoloc. Sweden) with spear-edge / verystrong qualifications and high-end indus

haskell-cafe - Wed, 09/10/2014 - 1:22pm
Dear Haskell developers, type theory developers, Agda/Epigram/Idris/Coq developers/enthusiasts abound in this community, We are searching the planet for great Haskell and Scala programmers right now for a really interesting spin-off now growing and flourishing after 2.5 years since it was founded. If you are a functional programmer this might be the most exciting job around with e.g. a very exciting customer "as close as a space station as you can get", and industrially entirely unique heavily research-based technology that we have developed now for several years. » https://www.linkedin.com/jobs2/view/19207355 You would help us develop our products further, the new constructive programming paradigm based on type theory carrying languages including domain-specific languages as never done before in the software industry … ( And yes, we are entirely based on (Martin-Löf) type theory, that's what we are all about. And we use Haskell for our development internally almost entirely, with some Ocaml etc
Categories: Offsite Discussion

Why not use cabal sandboxing?

Haskell on Reddit - Wed, 09/10/2014 - 1:18pm

A coworker & I were discussing cabal & sandboxing today and he pointed me to a blog post on setting up a Haskell environment. In it the author states, with much finality:

You should never use cabal sandbox. That way, you will only compile each needed library once. - http://yannesposito.com/Scratch/en/blog/Safer-Haskell-Install/index.html

Now, I understand his point, that you'll save time by having each library compiled globally instead of locally. But, some time ago (probably around cabal 1.15, 1.16 or so) when I was first getting started with Haskell, I remember trying to install Yesod. It didn't take long to delve deep into dependency hell with conflict after conflict. As a beginner this was extremely frustrating. I saw a post somewhere with an introduction to cabal-dev and started using sandboxing with that. Of course when cabal 1.18 came out with sandboxes built in, I upgraded immediately.

I have never had a single dependency conflict issue with cabal since switching to sandboxing. I actually use "sandboxing" now on every platform I develop on (Ruby's bundler with the "--path" option, virtualenv with python, node because npm). Since making this switch, I can honestly say I spend almost no time whatsoever mucking with my environment. I never run into packaging issues on any platform, and if I go away from a project for 6 months, it still works the same when I come back to it.

I've found sandboxing to be tremendously beneficial for me. I can understand why someone might want to avoid it if they don't like the time it adds to installs. For me it's worth it, but it might not be for everyone else.

Given all that, when I see someone say something like "You should never use cabal sandbox" it makes me question whether I'm missing something. Is there some reason besides time that I wouldn't want to use sandboxing? Is it somehow broken or does it cause problems I just haven't ran into yet?

EDIT: See comment below for a clarification on what the aforementioned blog post was referring to. If the author reads this, sorry for hastily criticizing your post, keep up the good work!

submitted by joefiorini
[link] [15 comments]
Categories: Incoming News

ANNOUNCE time-1.5

libraries list - Wed, 09/10/2014 - 9:43am
time-1.5 is now available from Hackage. <http://hackage.haskell.org/package/time> The source for time has now moved to GitHub: <https://github.com/haskell/time>. Send bug reports to the associated issue tracker. * Fixed a bug where tzset was not getting called on Windows. The other changes relate to Data.Time.Format: * time no longer depends on old-locale. The TimeLocale from old-locale has been replaced by a new one defined in Data.Time.Format. * The "intervals" field from TimeLocale has been removed, as it's not used. * The way time-zone abbreviations are parsed has changed. The parsing functions parse single-letter military abbreviations, and also time-zones found in the new "knownTimeZones" field of TimeLocale. Note that (knownTimeZones defaultTimeLocale) contains only the ten zone abbreviations mentioned in RFC822 sec. 5. This is the only standardised list of time-zone abbreviations I know of. Since the abbreviations are a many-to-many mapping, this should encourage people to think carefull
Categories: Offsite Discussion

Philip Wadler: Scots voting no to independence would be an astonishing act of self-harm

Planet Haskell - Wed, 09/10/2014 - 8:38am


George Monbiot writes stirring stuff on indy. Well-reasoned and well-documented.Imagine the question posed the other way round. An independent nation is asked to decide whether to surrender its sovereignty to a larger union. It would be allowed a measure of autonomy, but key aspects of its governance would be handed to another nation. It would be used as a military base by the dominant power and yoked to an economy over which it had no control. ... Most nations faced even with such catastrophes choose to retain their independence – in fact, will fight to preserve it – rather than surrender to a dominant foreign power....The fears the no campaigners have worked so hard to stoke are – by comparison with what the Scots are being asked to lose – mere shadows. As Adam Ramsay points out in his treatise Forty-Two Reasons to Support Scottish Independence, there are plenty of nations smaller than Scotland that possess their own currencies and thrive. Most of the world’s prosperous nations are small: there are no inherent disadvantages to downsizing.
Remaining in the UK carries as much risk and uncertainty as leaving. England’s housing bubble could blow at any time. We might leave the European Union.
...
How is the argument altered by the fact that Scotland is considering whether to gain independence rather than whether to lose it? It’s not. Those who would vote no – now, a new poll suggests, a rapidly diminishing majority – could be suffering from system justification.System justification is defined as the “process by which existing social arrangements are legitimised, even at the expense of personal and group interest”. It consists of a desire to defend the status quo, regardless of its impacts. It has been demonstrated in a large body of experimental work, which has produced the following surprising results.
System justification becomes stronger when social and economic inequality is more extreme. This is because people try to rationalise their disadvantage by seeking legitimate reasons for their position. In some cases disadvantaged people are more likely than the privileged to support the status quo. One study found that US citizens on low incomes were more likely than those on high incomes to believe that economic inequality is legitimate and necessary.
It explains why women in experimental studies pay themselves less than men, why people in low-status jobs believe their work is worth less than those in high-status jobs, even when they’re performing the same task, and why people accept domination by another group. It might help to explain why so many people in Scotland are inclined to vote no.
...
To deny this to yourself, to remain subject to the whims of a distant and uncaring elite, to succumb to the bleak, deferential negativity of the no campaign, to accept other people’s myths in place of your own story: that would be an astonishing act of self-repudiation and self-harm. Consider yourselves independent and work backwards from there; then ask why you would sacrifice that freedom.Scots voting no to independence would be an astonishing act of self-harm

A yes vote in Scotland would unleash the most dangerous thing of all - hope

(Monbiot is also the author of Heat, my favorite book on climate change.)
Categories: Offsite Blogs

Persistent Journal/Event queue Implementation

haskell-cafe - Wed, 09/10/2014 - 7:55am
Hello Cafe, I am looking for a Haskell implementation (or library binding) to some persistent journal/event queue software, something like Apache Kafka. My google-fu is lacking so I was not able to find anything but I might have been doing it wrong. Thanks, -- Arnaud Bailly FoldLabs Associate: http://foldlabs.com _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe< at >haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Categories: Offsite Discussion

GHC not seeing library MonadTrans instance

Haskell on Reddit - Wed, 09/10/2014 - 3:37am

Hello all. I am trying to compile a simple program that uses EitherT from the either package, but it errors like so:

import Control.Monad.Trans.Class import Control.Monad.Trans.Either import System.IO main :: IO (Either String [String]) main = runEitherT $ do lift getLine return [] {- Test.hs:7:9: No instance for (MonadTrans (EitherT String)) arising from a use of `lift' In a stmt of a 'do' block: lift getLine In the second argument of `($)', namely `do { lift getLine; return [] }' In the expression: runEitherT $ do { lift getLine; return [] } -}

Now, this is weird because either clearly defines a MonadTrans instance:

instance MonadTrans (EitherT e) where lift = EitherT . liftM Right

In fact, if I copy and paste that into my program, it compiles.

Is this a bug? Control.Monad.Trans.Either should define the instance.

I'm using GHC version 7.8.3, on a freshly installed and updated Haskell Platform (I reinstalled and updated just to check -- previously was running GHC 7.6).

submitted by lw9k
[link] [4 comments]
Categories: Incoming News

Mike Izbicki: Polymorphism in Haskell vs C++

Planet Haskell - Tue, 09/09/2014 - 6:00pm
Polymorphism in Haskell vs C++ posted on 2014-09-10 by Jonathan Dugan

Parametric polymorphism is when you write one function that works on many data types. In C++, this is pretty confusing, but it’s really easy in Haskell. Let’s take a look at an example.

Let’s say we want a function that calculates the volume of a box. In C++, we’d use templates so that our function works with any numeric type:

template<typename T> T boxVolume(T length, T width, T height) { return length * width * height; }

Templates have an awkward syntax, but that isn’t too much of a hassle. C++ has much bigger problems. What if in the course of writing your program, you accidentally pass in some strings to this function?

int main() { cout << boxVolume("oops","no","strings") << endl; }

We get this error when we compile with g++:

test.cpp: In instantiation of _T boxVolume(T, T, T) [with T = const char*]_: test.cpp:22:47: required from here test.cpp:8:19: error: invalid operands of types _const char*_ and _const char*_ to binary _operator*_ return length * width * height;

This error message is a little hard to understand because of the templates. If we had written our function to use doubles instead of templates:

double boxVolume(double length, double width, double height) { return length * width * height; }

We would get this simpler error message:

test.cpp: In function _int main()_: test.cpp:22:47: error: cannot convert _const char*_ to _double_ for argument _1_ to _double boxVolume(double, double, double)_ cout << boxVolume("oops","nope","bad!") << endl;

We see that this error is shorter and easier to use, as it clearly tells us we cannot pass string literals to our function. Plus there is no superfluous comment about our “instantiation” of boxVolume.

Now let’s try to write a polymorphic boxVolume in Haskell:

boxVolume :: a -> a -> a -> a boxVolume length width height = length * width * height

When we try to compile, we get the error:

test.hs:2:50: No instance for (Num a) arising from a use of `*' Possible fix: add (Num a) to the context of the type signature for boxVolume :: a -> a -> a -> a In the expression: length * width * height In an equation for `boxVolume': boxVolume length width height = length * width * height

Uh-oh! An error message! What went wrong? It says that we tried to use the * operator without declaring our parameters as an instance of the Num type class.

But what is a type class? This leads us to ad hoc polymorphism, also known as function overloading. Ad hoc polymorphism is when a function can be applied to different argument types, each with a different implementation. For example, the STL classes stack and queue each have their own push and pop functions, which, although they have the same names, do different things:

stack<int> s; queue<int> q; s.push(1); q.push(1); s.push(2); q.push(2); s.push(3); q.push(3); s.pop(); q.pop();

After the above code is executed, the stack s will be left with the numbers 1,2 while the queue q will be left with the numbers 2,3. The function pop behaves differently on stacks and queues: calling pop on a stack removes the item added last, while calling pop on a queue removes the item added first.

Haskell does not support function overloading, except through type classes. For example, if we were to specifically declare our own Stack and Queue classes with push and pop functions:

data Stack = Stack [Int] deriving Show data Queue = Queue [Int] deriving Show push :: Stack -> Int -> Stack push (Stack xs) x = Stack (x:xs) pop :: Stack -> Stack pop (Stack []) = Stack [] pop (Stack xs) = Stack (tail xs) push :: Queue -> Int -> Queue push (Queue xs) x = Queue (x:xs) pop :: Queue -> Queue pop (Queue []) = Queue [] pop (Queue xs) = Queue (init xs)

It results in a compiler error:

stack.hs:11:1: Duplicate type signatures for `push' at stack.hs:4:1-4 stack.hs:11:1-4 stack.hs:12:1: Multiple declarations of `push' Declared at: stack.hs:5:1 stack.hs:12:1 stack.hs:14:1: Duplicate type signatures for `pop' at stack.hs:7:1-3 stack.hs:14:1-3 stack.hs:15:1: Multiple declarations of `pop' Declared at: stack.hs:8:1 stack.hs:15:1

Changing the names of our push and pop functions to, say, stackPush, stackPop, queuePush, and queuePop would let the program compile.

A more generic way, however, is to create a type class. Let’s make a Sequence type class that implements our push and pop functions.

class Sequence s where push :: s -> Int -> s pop :: s -> s

This type class declaration says that any data type that is an instance of this Sequence type class can use the push and pop operations, or, in other words, can add and remove an Int. By making our Stack and Queue instances of the Sequence type class, both data types can have their own implementations of the push and pop functions!

instance Sequence Stack where push (Stack xs) x = Stack (x:xs) pop (Stack []) = Stack [] pop (Stack xs) = Stack (tail xs) instance Sequence Queue where push (Queue xs) x = Queue (x:xs) pop (Queue []) = Queue [] pop (Queue xs) = Queue (init xs)

Replacing our function definitions with these instantiations of the Sequence type class lets our program compile.

Type classes are also an important part of using templates in function definitions. In our function boxVolume, we got an error because we tried to use the * operation without declaring the type variable a as an instance of the Num type class. The Num type class is basically for anything that acts like a number, such as Int, Float, and Double, and it lets you use the common operations of +, -, and *.

Let’s change our function to declare that a is a Num:

boxVolume :: (Num a) => a -> a -> a -> a boxVolume length width height = length * width * height

This is called adding a class constraint. Whenever we want to declare a template function that relies on other functions, we have to add a class constraint that tells both the user and the compiler which types of data can be put into the function.

If we were to call boxVolume on strings, we would get this simple error message:

ghci> boxVolume "a" "b" "c" <interactive>:14:1: No instance for (Num [Char]) arising from a use of `boxVolume' Possible fix: add an instance declaration for (Num [Char]) In the expression: boxVolume "a" "b" "c" In an equation for `it': it = boxVolume "a" "b" "c"

The compiler tells us it can’t evaluate this function because strings aren’t numbers! If we really wanted to, we could make String an instance of the Num type class, and then this function would work! (Of course, why you would want to do that is beyond me.) That’s the power of parametric polymorphism combined with type classes.

So there you have it. In C++, although we can easily implement ad hoc polymorphism through function overloading, parametric polymorphism is a tricky beast. This is made easier in Haskell, especially with the use of type classes. Type classes guarantee that data passed in to functions will work, and guide the user into what they can pass into a function. Use type classes to your advantage when you next write a Haskell program!

Categories: Offsite Blogs

Mike Izbicki: Polymorphism in Haskell vs C++

Planet Haskell - Tue, 09/09/2014 - 6:00pm
Polymorphism in Haskell vs C++ posted on 2014-09-10 by Jonathan Dugan

Parametric polymorphism is when you write one function that works on many data types. In C++, this is pretty confusing, but it’s really easy in Haskell. Let’s take a look at an example.

Let’s say we want a function that calculates the surface area of a box. In C++, we’d use templates so that our function works with any numeric type:

template<typename T> T boxSArea(T length, T width, T height) { return length * width * height; }

Templates have an awkward syntax, but that isn’t too much of a hassle. C++ has much bigger problems. What if in the course of writing your program, you accidentally pass in some strings to this function?

int main() { cout << boxSArea("oops","no","strings") << endl; }

We get this error when we compile with g++:

test.cpp: In instantiation of _T boxSArea(T, T, T) [with T = const char*]_: test.cpp:22:47: required from here test.cpp:8:19: error: invalid operands of types _const char*_ and _const char*_ to binary _operator*_ return length * width * height;

This error message is a little hard to understand because of the templates. If we had written our function to use doubles instead of templates:

double boxSArea(double length, double width, double height) { return length * width * height; }

We would get this simpler error message:

test.cpp: In function _int main()_: test.cpp:22:47: error: cannot convert _const char*_ to _double_ for argument _1_ to _double boxSArea(double, double, double)_ cout << boxSArea("oops","nope","bad!") << endl;

We see that this error is shorter and easier to use, as it clearly tells us we cannot pass string literals to our function. Plus there is no superfluous comment about our “instantiation” of boxSArea.

Now let’s try to write a polymorphic boxSArea in Haskell:

boxSArea :: a -> a -> a -> a boxSArea length width height = length * width * height

When we try to compile, we get the error:

test.hs:2:50: No instance for (Num a) arising from a use of `*' Possible fix: add (Num a) to the context of the type signature for boxSArea :: a -> a -> a -> a In the expression: length * width * height In an equation for `boxSArea': boxSArea length width height = length * width * height

Uh-oh! An error message! What went wrong? It says that we tried to use the * operator without declaring our parameters as an instance of the Num type class.

But what is a type class? This leads us to ad hoc polymorphism, also known as function overloading. Ad hoc polymorphism is when a function can be applied to different argument types, each with a different implementation. For example, the STL classes stack and queue each have their own push and pop functions, which, although they have the same names, do different things:

stack<int> s; queue<int> q; s.push(1); q.push(1); s.push(2); q.push(2); s.push(3); q.push(3); s.pop(); q.pop();

After the above code is executed, the stack s will be left with the numbers 1,2 while the queue q will be left with the numbers 2,3. The function pop behaves differently on stacks and queues: calling pop on a stack removes the item added last, while calling pop on a queue removes the item added first.

Haskell does not support function overloading, except through type classes. For example, if we were to specifically declare our own Stack and Queue classes with push and pop functions:

data Stack = Stack [Int] deriving Show data Queue = Queue [Int] deriving Show push :: Stack -> Int -> Stack push (Stack xs) x = Stack (x:xs) pop :: Stack -> Stack pop (Stack []) = Stack [] pop (Stack xs) = Stack (tail xs) push :: Queue -> Int -> Queue push (Queue xs) x = Queue (x:xs) pop :: Queue -> Queue pop (Queue []) = Queue [] pop (Queue xs) = Queue (init xs)

It results in a compiler error:

stack.hs:11:1: Duplicate type signatures for `push' at stack.hs:4:1-4 stack.hs:11:1-4 stack.hs:12:1: Multiple declarations of `push' Declared at: stack.hs:5:1 stack.hs:12:1 stack.hs:14:1: Duplicate type signatures for `pop' at stack.hs:7:1-3 stack.hs:14:1-3 stack.hs:15:1: Multiple declarations of `pop' Declared at: stack.hs:8:1 stack.hs:15:1

Changing the names of our push and pop functions to, say, stackPush, stackPop, queuePush, and queuePop would let the program compile.

A more generic way, however, is to create a type class. Let’s make a Sequence type class that implements our push and pop functions.

class Sequence s where push :: s -> Int -> s pop :: s -> s

This type class declaration says that any data type that is an instance of this Sequence type class can use the push and pop operations, or, in other words, can add and remove an Int. By making our Stack and Queue instances of the Sequence type class, both data types can have their own implementations of the push and pop functions!

instance Sequence Stack where push (Stack xs) x = Stack (x:xs) pop (Stack []) = Stack [] pop (Stack xs) = Stack (tail xs) instance Sequence Queue where push (Queue xs) x = Queue (x:xs) pop (Queue []) = Queue [] pop (Queue xs) = Queue (init xs)

Replacing our function definitions with these instantiations of the Sequence type class lets our program compile.

Type classes are also an important part of using templates in function definitions. In our function boxSArea, we got an error because we tried to use the * operation without declaring the type variable a as an instance of the Num type class. The Num type class is basically for anything that acts like a number, such as Int, Float, and Double, and it lets you use the common operations of +, -, and *.

Let’s change our function to declare that a is a Num:

boxSArea :: (Num a) => a -> a -> a -> a boxSArea length width height = length * width * height

This is called adding a class constraint. Whenever we want to declare a template function that relies on other functions, we have to add a class constraint that tells both the user and the compiler which types of data can be put into the function.

If we were to call boxSArea on strings, we would get this simple error message:

ghci> boxSArea "a" "b" "c" <interactive>:14:1: No instance for (Num [Char]) arising from a use of `boxSArea' Possible fix: add an instance declaration for (Num [Char]) In the expression: boxSArea "a" "b" "c" In an equation for `it': it = boxSArea "a" "b" "c"

The compiler tells us it can’t evaluate this function because strings aren’t numbers! If we really wanted to, we could make String an instance of the Num type class, and then this function would work! (Of course, why you would want to do that is beyond me.) That’s the power of parametric polymorphism combined with type classes.

So there you have it. In C++, although we can easily implement ad hoc polymorphism through function overloading, parametric polymorphism is a tricky beast. This is made easier in Haskell, especially with the use of type classes. Type classes guarantee that data passed in to functions will work, and guide the user into what they can pass into a function. Use type classes to your advantage when you next write a Haskell program!

Categories: Offsite Blogs

api-tools questions

haskell-cafe - Tue, 09/09/2014 - 2:02pm
Hi All, I have a question concerning the api-tools package. Its not clear from the tests, sources or the tutorial how I can use other date/time formats that the default `utc` type can handle. I'm trying to wrap a JSON API that is not under my control, so I have to adhere to whatever I get back from it. Could anybody with experience with the package point me to some example, relevant bits in the sources or a tip how to do it? I'm planning to create some more documentation around the package to contribute back once I figured out a few more details, because I think its quite a useful abstraction when dealing with (foreign) APIs IMO. Thanks already for any hints, karsten
Categories: Offsite Discussion

Reversing a fixed-length vector

haskell-cafe - Tue, 09/09/2014 - 1:55pm
Hi, I'm playing around with Type Families so I decided to implement a simple fixed-length Vect of Integers. Here is my straightforward implementation (ghc 7.8.3): https://gist.github.com/anonymous/d838e68ce6a02412859f As you can see, I'm trying to implement a reverse function for my vectors which guarantees that the output vector is the same size as the input one. I tried to express this constraint at the type level. The problem is that I can't have ghc to type check the reverse function in the non-trivial case: _________________ Could not deduce (Plus n1 (S m) ~ S (Plus n1 m)) from the context (n ~ S n1) bound by a pattern with constructor CV :: forall n. Int -> Vect n -> Vect (S n), in an equation for ‘vecReverse’ at vect3.hs:30:13-18 Expected type: Vect (Plus n m) Actual type: Vect (Plus n1 (S m)) _________________ Iit has to do with the fact that the type checker can't deduce that: Plus n1 (S m) ~ S (Plus n1 m) ~ Plus (S n1) m ~Plu
Categories: Offsite Discussion

Warnings for unhandled exceptions

haskell-cafe - Tue, 09/09/2014 - 1:38pm
L.S., I was reading about the Aardvark language [0] and the robustness they intend to implement in it by, amongst others, catching each possible exception. I wonder, is it possible to implement compiler warnings for unhandled exceptions in Haskell? One of the strong points of Haskell is the type checking and clearly identifying functions with side effects, but exceptions are not reflected by the type of a function. It would be useful if the compiler gave a warning for each type of exception, for each expression, that is not handled by the program. Regards, Henk-Jan van Tuyl [0] http://aardvarklanguage.sourceforge.net/
Categories: Offsite Discussion

How do you structure a program to support logging?

Haskell on Reddit - Tue, 09/09/2014 - 12:49pm

I'm a beginner Haskell programmer. I'm trying to understand the consequences of coding with the IO monad.

In my first program, I found that I wanted to see how evaluation of low-level functions was proceeding and to monitor intermediate values. In other languages a convenient way to accomplish this would be with logging statements in the code, which might be turned on or off with a command line debug switch.

In Haskell, that means that each pure function now must return an IO monad, in order that it have the possibility to generate output. It seems that I have to change the return type of each function in the chain down to the lowest level one that can generate a log entry.

I see that there are a number of Haskell logging modules available, but I haven't found any tutorial that addresses architectural questions of how to organize your codebase with logging.

Is this the right way to approach this problem? Is there some better way to keep logging separate from logic? Or is there some completely different way of monitoring intermediate values that is more appropriate than logging in Haskell?

submitted by swenty
[link] [32 comments]
Categories: Incoming News