Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

It's perfectly idiomatic Haskell to annotate all your functions with an effect you believe they should all have.



The only reason this is idiomatic is because there is no better way. That's the entire point I'm making... Haskell prides itself in writing generic and reusable functions. This then is then thrown out of the window with the kitchen sink monad. Very understandable, because everything else sucks.

That precisely why I think this is a great shortcoming of the language.


It's not a shortcoming of the language; it's a shortcoming of the goal! You can't have both the goal of fine-grained effect tracking and the goal of not having to make fine-grained changes when effects change. They're incompatible goals in any language.

The strength of Haskell is that it allows you to achieve the first goal if you want. Most languages don't (pretty much no other language, actually).


That's an extremely limited point of view. Just because Haskell allows precise specification does not mean it is impossible to disallow loose specification. In fact that's one of the strongest values of Haskell's type system. For example you can overconstrain your head function

    head :: [Int] -> Int
But you can also just leave out the type signature all together to let the type checker figure out the most generic type. You can have your cake and eat it too.

You can even almost do what I want with partial type signatures. Just sprinkle it everywhere inside your constraints. GHC will automatically pick the right constraints. At the call site you actually care for the definition you can not use the partial type signature. The great disadvantage of this is that you now introduce ANY constraints into your type signature and you lose your types as documentation.

But that doesn't have to be

You could have a constraint with something like `UseMonadSubset (...)` which works almost like partial type signature. GHC should infer 0 or more of the monads insde `UseMonadSubset` as the actuall constraint. `

Then you could write something like:

    fibonacci :: UseMyMonadSubset m => m Int
    fibonacci = -- Uses only MonadState (Int, Int, Int)

    -- Type checks because type checker can see fibonacci ONLY uses MonadState
    foo :: MonadState (Int, Int, Int) m => Int
    foo = fibonacci

    bar :: UseMonadSubset m => Int
    bar = fibonacci
Which allows for precise specification if you want to and if you don't you let the type checker figure it out. You may even be able to implement this as GHC type checker plugin.


It's an interesting idea but I can't say I feel that would solve a problem I've ever had. In fact, I always completely annotate top-level definitions with their types. I never want them inferred. And I've never felt it too burdensome to fix up a call stack when adding a new effect. But if you consider that a weakness of Haskell then so be it!




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: