Hacker News new | past | comments | ask | show | jobs | submit login

How far can you go without monads and category theory? I was looking at Clean which developed in parallel with Haskell and uses uniqueness typing instead of IO/mutation monads. Seems like it would be less offputting for a newcomer. Clean lacks community and a package manager, I believe which makes it less attractive. The language itself seems like a sweet spot for me.



If you want to be productive in Haskell, the Monad typeclass is an important tool to familiarize yourself with. That said, unless you are working on the internals of a few libraries, you don't really ever need to know serious category theory in order to be very productive. If you don't already have a background in abstract algebra or category theory, I think a better approach to learning these abstractions is slowly work through the typeclassopedia[0] while solving problems the naive or clunky way and then start to use the fancy-name abstractions (e.g. Functor, Applicative) as you see how they could be useful.

On that front, the Monad typeclass is far more general and useful than just for IO and State, so if you are thinking of it as primarily a hack to deal with those, you probably won't get the hype. In addition, it's really useful to work with a large number of examples of different Monad instances (IO, State, Maybe, List, STM[1] if want to get a bit further into the deep end) instead of just staring at the methods in the typeclass and hoping it make sense. It's a pretty broad abstraction, so it will only make sense if you are familiar with what it's abstracting.

[0] https://wiki.haskell.org/Typeclassopedia

[1] http://book.realworldhaskell.org/read/software-transactional...


The other partial reason for not wanting to know is that I can't then unknow. Willfull ignorance it is. Can those who know say they're happy using languages on the daily without the features you miss and think in?


Thanks for this info. What I really want to know is the value prop for learning/using monads etc. The examples of IO, State, Maybe, List, STM given seem like they'd be dealt with just fine in Clean.


I think it's important to be precise about how the monad abstraction and type system features interact in order to combine pure and impure code. I wrote a comment elsewhere in the thread (https://news.ycombinator.com/item?id=20112333) where I conclude that while the monad abstraction is useful for making a usable interface and writing programs which are agnostic to how their state is implemented, the fundamental work of distinguishing pure and impure computations is accomplished with a combination of type system features and compiler magic.

The case is exactly the same for the Clean language as for Haskell and indeed Clean has Monad instances for all of the types I mentioned aside from STM, so there are no concerns with dealing with those monadic abstractions in Clean. (https://imgur.com/a/sjsDiZq, https://cloogle.org/#using%20Monad) Since IO is Haskell's type that marks impure computations, we can compare Haskell's implementation to the equivalent one in Clean (interface: https://cloogle.org/src/#Platform/System/IO;line=10, implementation: https://cloogle.org/src/#Platform/System/IO;icl)

In Clean, IO is implemented as follows:

    :: IO a = IO .(*World -> *(a, !*World))
In Haskell, it is:

    newtype IO a = IO (State# RealWorld -> (# State# RealWorld, a #))
(for full context see: http://hackage.haskell.org/package/ghc-prim-0.5.3/docs/src/G..., the related monad instance is here: http://hackage.haskell.org/package/base-4.12.0.0/docs/src/GH...)

These both implement IO as a function which takes the state of the world as its input and returns a new state of the world as it's output. This is encoded using the state transformation that I mention in the other post (https://acm.wustl.edu/functional/state-monad.php) Both implementations also go on to define Monad instances for their new IO type. The major difference is that the Haskell standard library only exposes bindIO and returnIO to the user and hides the internals of IO from the user and Clean allows the implementation to be a normal library.

That difference is Clean's uniqueness types showing their strength. Clean can explicitly expose it's predefined World type (https://cloogle.org/doc/#CleanRep.2.2_6.htm;jump=_Toc3117980...) to the user with the guarantee that you can't write a function of type IO a -> a because it would violate the uniqueness properties and thus be a compilation error. Haskell instead uses the module system to keep State# RealWorld from being exposed to the user. This means that if you as a user want a different set of abstractions for impurity in Clean, you can build from the World level rather than needing to construct it out of what can be done with bindIO and returnIO. For details on what's going on with State# see https://www.fpcomplete.com/blog/2015/02/primitive-haskell

From the perspective of "the value prop for learning/using monads", this discussion leaves us in a worse place than where we started because the conclusion is that uniqueness types aren't a get out of monads free card and that Clean uses the many of the same Monad-related abstractions as Haskell does and uses them for the same purposes. In order to not leave you out in the cold as to the value prop for the monad abstraction, you can see how it works for a number of different Monad instances in Tikhon's answer on Quora (https://www.quora.com/What-are-monads-in-functional-programm...), though he chooses to use join, fmap, and return as the fundamental parts of a Monad, rather than bind and return, as I have here. As he touches on in his discussion, it's common and straightforward to implement one definition in terms of the other, so anything you learn from about that definition can be ported the definition I use without much fuss, so don't worry if it doesn't match at first. What this means is that if you have a tools in the standard library that only depend on features of Monad, you can use the same small collection of functions to solve a ton of problems.


This is want I needed to hear. I haven't used either Clean nor Haskell other than playing with them and my introduction to Clean seemed more lightweight where there some syntax to make uniqueness seem easier than the same in Haskell. On further reading, when seeing the u:[...] syntax rather than * I can see they're really quite the same. They way the uniqueness attributes are described seems like a separate axis than data types where in Haskell there's just so much type. Also the docs for Clean avoids using category theory terms for the most part, getting you started by showing you the syntax to do certain things.

I expect to be coming back to this comment and the references quite a few times until it clicks for me.


Finally think I get monads. And I don't believe it's hard to explain or hard to understand just that almost all the explanations are bad and you have to go through so many of them to put the pieces together.


> How far can you go without monads and category theory?

Without monads? Not pretty far, but they're far simpler than the wide web would have you believe.

Without category theory? Sky's the limit. I say this as experienced Haskell programmer occasionally dabbling in category theory for funsies. The practical impact on "how easy is it to program Haskell" of category theory is basically zero.


I didn't mean how far in Haskell without monads. I meant how far in something else like Clean that uses uniqueness typing to handle some of the same aspects where monads would be used with Haskell.


Not used Clean, but it sounds interesting.

What i'd love is an imperative language where you declare what effects a method can have and the compiler enforces them. E.g. if it promises not to mutate any parameters, it can only call functions that make the same promise etc.


Idris isn't imperative (Haskell-like with dependent types), but offers features like those:

http://docs.idris-lang.org/en/latest/effects/depeff.html

    readInt : Eff Bool [STATE (Vect n Int), STDIO]
                       [STATE (Vect (S n) Int), STDIO]
http://docs.idris-lang.org/en/latest/st/machines.html

    logout : (store : Var) -> ST m () [store ::: Store LoggedIn :-> Store LoggedOut]
They're both implemented within Idris, as libraries/modules, rather than being compiler magic:

- https://github.com/idris-lang/Idris-dev/blob/master/libs/con...

- https://github.com/idris-lang/Idris-dev/blob/master/libs/eff...

I think it'd be possible to write similar effect systems in other dependently typed languages like ATS, which is a relatively imperative language (C+ML-like).


That sounds very similar to Rust. Mutations and even memory lifetime are specified in the type system.


This is how Pony does it, basically. See [Reference Capabilities](https://tutorial.ponylang.io/reference-capabilities.html).




Consider applying for YC's Spring batch! Applications are open till Feb 11.

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

Search: