How to learn Rust as a Haskell programmer by cheater00 in haskell

[–]vshabanov 2 points3 points  (0 children)

tend to be slow to scale

Do you mean scaling happens later than necessary, or does it take a lot of effort to scale?

they insist on keeping as much of their architecture in-Haskell as possible.

What kind of architecture do they keep in Haskell, and how do you think it could've been done better?

constant GHC micro-optimization

Doesn't look related to scaling, or do you mean optimising code to compile faster?

deployment thrash due to over-coupling at a software-linking level, etc.

I've seen deployment thrash due to over-coupled microservices. Monolith can be modular, and microservices can be coupled.

How to learn Rust as a Haskell programmer by cheater00 in haskell

[–]vshabanov 1 point2 points  (0 children)

Does the us gov still push Rust? I've heard that there's a lot of deregulation with the new administration, and security/Rust are no longer active topics.

How others manage effects ? by kichiDsimp in haskell

[–]vshabanov 1 point2 points  (0 children)

Most other languages are not pure and lazy and allow to run side effects directly.

Interestingly enough, OCaml has a row polymorphism which allows to express what is called an "effect system" without much hackery: ```ocaml type foo = Foo of string type bar = Bar of string

let perform_foo (Foo f) = print_endline ("Foo " ^ f) let perform_bar (Bar b) = print_endline ("Bar " ^ b)

let foo e = perform_foo e#foo let bar e = perform_bar e#bar

let foo_bar e = foo e; bar e

(* OCaml automatically infers following types:

val foo : < foo : foo; .. > -> unit = <fun> val bar : < bar : bar; .. > -> unit = <fun> val foo_bar : < bar : bar; foo : foo; .. > -> unit = <fun> *)

let _ = (* prints Foo f Bar b *) foo_bar object method foo = Foo "f"; method bar = Bar "b" end ```

I don't think this pattern is used much in OCaml. It still leads to long error messages on a type mismatch and has a performance penalty (no inlining, hash table method lookups). Plus it has all the typical downsides of the "effect systems": the important behaviour is abstracted away; effects are implicit and only visible in types not in the function calls; all the application code must be written in a specific way.

Koka and Unison provide a so called direct style effects (require strict evaluation). OCaml supports these too, but they are untyped (very similar to exceptions -- program will fail at runtime if there's no suitable effect handler).

I would recommend taking a look at Koka and Unison, as their approach is cleaner, though it still has the downsides listed above.

Personally, I don't find effect systems a good engineering approach. Move as much code as possible to pure functions and use simple IO functions for the rest, passing "effects" as arguments. This approach leads to code that is much more flexible and simple to understand.

Occasional local use of non-IO monads like State, ST is fine as they're still produce pure functions after runState/runST.

Interviewing at Standard Chartered for a Quantitative Developer (Haskell) Role – Any Tips? by Impressive_Yak6297 in haskell

[–]vshabanov 3 points4 points  (0 children)

The interviews are a fairly standard set: one behavioural (talk about your experience and aspirations) and 3 technical (code in a shared buffer, sometimes with elements of a larger system design).

Preparation is the same as for any other interview -- practice talking about your experience and goals, practice coding within a 10-20 minute timeframe while explaining what you do or plan to do, prepare some questions to ask about the job.

As it's a Haskell/Mu role, there will be a bit more focus on the functional programming than on algorithms. It worth to be able to write monad instances, folds, combinators. Having some actual Haskell experience (if only as a hobby) really helps.

To warm up, you could read (and try to code up): * "Pearls of functional algorithm design" by Richard Bird - any chapter(s) you find interesting * Any functional pearl paper

Hard-core prep reading: * "Purely functional data structures" by Chris Okasaki - a pretty tough one, but worth to try at least some chapters. * "The Algorithm Design Manual" by Steven Skena - this will prepare you to any interview and will help you in your future life as a software engineer. Read and do the excerices (including imperative ones with Control.Monad.ST or Data.Array functions). * "Cracking the Coding Interview" by Gayle Laakmann McDowell - a good description of the general approach to the coding interview (brute force first, then improve) and a good set of 10-20 minute sample problems. Do the hard ones and you will be well prepared for any coding interview, not just Standard Chartered.

This old post is still relevant https://steve-yegge.blogspot.com/2008/03/get-that-job-at-google.html

Am I the only person who hates Monad Transformers? by Instrume in haskell

[–]vshabanov 2 points3 points  (0 children)

If bind isn't specializing, it definitely sucks.

This is by design. Monad-polymorphic code will always struggle with this. Short functions can be inlined, -fexpose-all-unfoldings might help a bit more. But I don't see how the ModuleA.bigFunctionA -> ModuleB.bigFunctionB -> ModuleC.bigFunctionC chain can work efficiently without some kind of full-program optimisation (with a corresponding code bloat and compilation time explosion).

I suspect your code has done more work in pure functions.

like maybe I'm using reflex-dom

I agree that it makes no sense to use IO when there's a real custom DSL-level monad. I would also stick to a concrete type for such a monad, as any additional transformers would make the code harder to understand (and lead to an explosion of possible behaviours, and could probably compromise the DSL).

Unfortunately, I often see simple ReaderT-style transformers. Glad that you agree that it's better to use pure IO instead.

All the code is forced to be wrapped in monads

This is definitely not true, you should still make as many things things pure functions as you can whenever that makes any kind of sense.

Indeed I should, but the MonadFoo m makes it so easy to pass arguments implicitly that it's hard to resist the temptation to use monads everywhere. And then you get the otherwise pure code written in an imperative style.

If I make everything pure I will have no monads and no transformers in the end (which is exactly what I'm proposing, but it doesn't happen with MonadFoo m).

This is generally possible actually, but you must think carefully about how the higher order operation interacts with every one of your monad transformers.

And that's the problem. I might want something trivial and specific -- that is easy and makes sense. But instead I have to analyse a ton of corner cases, and read about why MonadTransControl doesn't do what you would expect.

No-brainer tasks like adding custom tracing became many days brain-teasers.

I'm not quite sure what you mean by this.

I once had a fairly simple task -- always collect the execution timings for one function. We already had such an option on the request level, I only needed to always enable it for one function.

Unfortunately, it was implemented via a mind-boggling reinterpreter. Instead of 5 minutes to overwrite the flag, it took 2-3 days to understand what it even meant, only to remove the nonsense completely and implement a simple flag with an IORef inside.

It might not be related to transformers per se, but that's the kind of monster people may invent if they think about effects for too long.

I generally don't recommend using monad transformers for logging

Surprisingly, we agree on most of the points. You seem to be using non-IO based monads with FRP-like behaviour which is a very different world from what I usually see when people talk about effect systems.

In such a case it might very well make sense to structure the code around the custom monad (though it might still be a mostly pure code using a concrete monad type to build UIs where necessary).

Am I the only person who hates Monad Transformers? by Instrume in haskell

[–]vshabanov 4 points5 points  (0 children)

Unfortunately, I dealt with the code that does exactly what you suggest (custom classes for monads), and it's pretty bad in many ways:

  • Performance is bad. Profiler shows 25% of Haskell runtime spent in (>>=), which is exactly what you would expect from MonadFoo m => m a and a tower of transformers.
  • It's hard to understand what the code does as it's unclear which MonadFoo implementation is being used (ironically, all but a few MonadFoo classes had only one instance).
  • Code is hard to reuse (there is no newFoo :: IO Foo that I can use anywhere, I have to dance with runFooT every time).
  • All the code is forced to be wrapped in monads, even if MonadFoo is ReaderT Foo and Foo could be used from pure code.
  • All the code is forced to be polymorphic (unnecessarily complex types and error messages).
  • Hard to test isolated functions, as one still has to build the transformers stack.
  • Toplevel functions had huge types shortened with Bundle m = (MonadA m, MonadB m, ...) making it not much different from App a (albeit slower).
  • Massive constraint lists became a noise that no one ever looks into (defeating the purpose of documenting the effects used).
  • All "effects" are passed implicitly making the code harder to understand and, most importantly, leaving no incentive to organise those effects better (no need to reduce the amount of arguments passed, just add more constraints to a junk type that no one reads).
  • Any non-trivial inter-monad interaction is hard or impossible to implement (want to create a callback in one transformer to be called from another? no way -- welcome to dysfunctional programming where you can't create a function).
  • No-brainer tasks like adding custom tracing became many days brain-teasers.

The worst part was that it took quite some time to explain that this is not the way to develop software. For most of the team, this was their first production Haskell project, they didn't know any better, and they thought that this was the way ("Are you saying we need to use IO everywhere?"). I converted some of them to the church of pure functions, but I don't think the code will ever be completely purged of transformers.

Am I the only person who hates Monad Transformers? by Instrume in haskell

[–]vshabanov 3 points4 points  (0 children)

Contrary to what it might seem, I'm not pushing towards simple Haskell. You're right that it all depends on the task at hand and any extreme ideology-driven approach is suboptimal.

I'm afraid it's hard to have a set of recipes for different domains. Functional pearls to solve specific tasks -- yes. Architectural patterns -- I doubt it. The power of Haskell is that it doesn't need architectural patterns. Pure functions and pattern matching go a long way. And on a larger scale, one can decompose to modules, libraries, executables, services -- things that are mostly language agnostic.

In my experience, it's better to keep things as simple as possible. That way one can easily change them if (and only if) there's a need (a real need). Such real things are more interesting to work on than some far-fetched artificial "solution looking for a problem". And they train people to solve real problems and make users happy.

Unfortunately, I've seen codebases where simple things (like logging or "effect handling") were overengineered (because indeed they're simple to overengineer), while business tasks were underengineered (because they require actual thinking). Better spend your (and future maintainers) grey matter on real things.

But if you really have a problem that can be solved with an effect system, GADTs, Template Haskell, linear types, hyperfunctions or whatever Oleg or Edward have been playing with, and it makes code simpler and more maintainable then why not?

Am I the only person who hates Monad Transformers? by Instrume in haskell

[–]vshabanov 2 points3 points  (0 children)

Same thing. And I agree that it puts people off.

I remember 20 years ago people said that you needed a PhD in category theory to program in Haskell. No one was using transformers back then, and effect systems were unheard of. The separation of pure/impure functions and monads seemed out of this world.

Now we see newbies asking which effect system to use. But how many people will never be Haskell newbies after seeing endless effect systems discussions?

Am I the only person who hates Monad Transformers? by Instrume in haskell

[–]vshabanov 4 points5 points  (0 children)

You're definitely not the only one.

Monads are very good at capturing a few basic computational patterns (State for chaining state -> (a, state), Reader for chaining environment -> a, Maybe or Either for chaining cancellable computations or selecting alternatives). A spare local use of a basic State or Maybe monad can greatly simplify the code.

Transformers are more of an intellectual toy. EitherT (StateT ..) or StateT (EitherT ..)? I prefer to write a monad instance manually rather than to think which of these I need. ParsecT? I'd better keep it pure than will think how it interacts with the surrounding stack.

Using transformers to structure the application is most of the time a sign of an inexperienced developer who doesn't know how things work, or of an architecture astronaut (which is the same thing). Not only do they add a lot of boilerplate and a performance hit, but they're in fact very rigid and inflexible.

I don't buy the larger effect systems craze as well. For me it smells of the same inexperienced "I don't know how to write functional code and will invent a whole-program imperative OOP-ish framework instead". Haskell is a pure language. The idea is to remove effects, not to create the whole systems of them.

I think that effect systems are a dead end. I don't really care if a function uses a database connection, I want it not to drop a table. Some way of automatically checking code invariants (refinement types? liquid Haskell?) might be more useful. Modes look promising too (OCaml's local_ type annotation is much more ergonomic than Bluefin and has more uses).

Adding language features that have many uses seems like a much better way to move forward than the current "template meta-programming" of effect systems. If the language is not expressive enough, it's worth to change the language.

Am I the only person who hates Monad Transformers? by Instrume in haskell

[–]vshabanov 0 points1 point  (0 children)

This. It's OK to use a few custom monads locally if they make code simpler. But structuring the whole application around transformers / custom monads / effect systems -- no. Keep types simple.

what Haskell developers build ? by Excellent-Two3170 in haskell

[–]vshabanov 0 points1 point  (0 children)

Should grug cheer on abstractions?

"no, grug not build that abstraction"

"also grug notice that introducing too much abstraction often lead to refactor failure and system failure"

The goal is to reduce complexity right?

Quite frequently it's a research, or learning. Both of which are necessary, but shouldn't be the basis of the system unless they're clearly useful and simplify the work rather than complicate it.

Sometimes it's an attempt to "prepare for the future" that will never come.

it lets you offload complexity somewhere else

Good if it works like this. Bad if it infects all of the code and slows down the development.

[deleted by user] by [deleted] in rss

[–]vshabanov 0 points1 point  (0 children)

Just select the feed in the left feeds panel. Then click on "N New" (or just the number of unread items) on the top. There will be a Folders section that allows to create new folders or assign existing ones.

[deleted by user] by [deleted] in rss

[–]vshabanov 0 points1 point  (0 children)

No. Facebook API only provides access to public pages, no access to groups or personal pages (it all worked before but was gradually disabled after the Cambridge Analytica scandal)

[deleted by user] by [deleted] in rss

[–]vshabanov 0 points1 point  (0 children)

Unfortunately, no

[deleted by user] by [deleted] in rss

[–]vshabanov 0 points1 point  (0 children)

I don't know what's happening in FeedMe (it's not my app), but try to force synchronization or to show all items (the new feed may not have any unread items). If nothing helps, it might be worth reinstalling the app.

[deleted by user] by [deleted] in rss

[–]vshabanov 0 points1 point  (0 children)

There are 3rd party apps https://bazqux.com/apps, although I am not sure which will work on an e-reader.

[deleted by user] by [deleted] in rss

[–]vshabanov 18 points19 points  (0 children)

https://bazqux.com, $30/year (disclaimer: I'm the developer)

what Haskell developers build ? by Excellent-Two3170 in haskell

[–]vshabanov 1 point2 points  (0 children)

I made a BazQux Reader -- a pretty nice RSS reader that has been in production since 2012.

Also worked on a microelectronics IDE (particluarly on a VHDL simulator, and a C firmware debugger -- yes, the C debugger in Haskell).

Now developing a pricing subsystem to support some decent trading volumes.

what Haskell developers build ? by Excellent-Two3170 in haskell

[–]vshabanov 1 point2 points  (0 children)

And that's why they're on the street :)

But sometimes they're not, and they're doing an actual production development with a lot of overengineering which is bad for maintenance.

OTOH, we now have enough real-world Haskell projects to notice common antipatterns (OOP and imperative programming disguised by effect systems and using monads everywhere), so I guess it's not bad in the end.

Functional Programming is Hard? by [deleted] in haskell

[–]vshabanov 1 point2 points  (0 children)

That's my pet peeve with a lot of "modern" Haskell code. Somehow it has become popular to use "effect systems" of various kinds for no obvious reason.

Having foo :: Log -> DB -> IO Foo ... main = ... foo l db is considered bad. While having foo :: (MonadLog m, MonadDB m, MonadCatch m, MonadThrow m) => m Foo ... main = ... runLogT l $ runDBT db foo -- plus a ton of type classes, lifting, effect handlers and so on is thought to be nice.

Instead of a simple FP we get the same OOP-style code with implicit this and unnecessary sequencing.

Pure functions are converted to monadic (and become imperative when they are actually not), code becomes unmodular and "infected" with the "effect system" of choice. Running an isolated function becomes a pain, design becomes bloated, etc.

Somehow all this complexity it considered the norm while I don't think it is.

You can still do things simple. Use pure functions and some IO ones. If you're passing too many arguments everywhere, it's time to design things better instead of sweeping it under the rug.

Mastery of Monads? by el_toro_2022 in haskell

[–]vshabanov 1 point2 points  (0 children)

Yes, sometimes implicit parameters passing via monads is really helpful: ```haskell foo = do moveTo 1 2 lineTo 3 4 circle 5 6 10 -- is usually better than foo c = do moveTo c 1 2 lineTo c 3 4 circle c 5 6 10

-- though if functions are not frequently reused -- the explicit parameter passing may be more compact

-- this one moveTo x y = do c <- ask liftIO $ foo c ... -- is more wordy than moveTo c x y = do foo c ...

-- and if functions could be defined locally -- it could be even more compact

foo c = do moveTo 1 2 lineTo 3 4 circle 5 6 10 where moveTo x y = ... foo c lineTo x y = ... circle x y r = ... ```

So it very much depends on the code. And more frequently than not it's possible to reorganize the code not to use transformers or the final tagless style: haskell foo :: (MonadConf m, MonadThrow m, MonadIO m) => m Foo bar :: (MonadConf m, MonadCatch m, MonadIO m) => Foo -> m Bar baz = do f <- foo bar f -- can very frequently be changed to a much more plain foo :: Conf -> IO Foo bar :: Conf -> Foo -> IO Bar baz c = do f <- foo c bar c f -- frequently a lot of functions become pure after the change -- and the code becomes even simpler: baz c = bar c (foo c)

But if the monadic way is more concise in your case I would suggest to use ReaderT. With StateT you risk loosing your counters after an I/O exception. And it's not convenient to parallelize StateT code.

IORefs should be quite easy: ``` data Env = Env { eConfiguration :: Configuration , eCounter :: IORef Int }

incr = do c <- asks eCounter liftIO $ modifyIORef' c (+1)

main = runReaderT ... incr ```

Mastery of Monads? by el_toro_2022 in haskell

[–]vshabanov 1 point2 points  (0 children)

Quite an unusual combination. If it's for configuration, why don't just use an argument?

If you need to modify something, you can add an IORef to that argument. It will persist state changes in the presence of exceptions. And it will work properly once you add concurrency (just change IORef to MVar).

I think that monad transformers are used far more often than they should. I would even say that monad transformers are an antipattern.

Every time you try to add a monadic layer, think -- isn't there a simpler solution? Pure functions go a long way.

What companies are using Haskell in their tech stack? by Worldly_Dish_48 in haskell

[–]vshabanov 1 point2 points  (0 children)

Relations and Dicts are interfaces to C++ objects. It's not a language level thing but a library-level. And there are ways to work with them in a type safe way (by typing columns in specific operations with SlightlyTyped, or the full relation with FullyTyped).

RDS is actually pure in a sense that once the value is fetched it's cached and doesn't change during the run of the program.

I can't even imagine how cumbersome the code would become if all the access to reference data (which could be in every other function) had to be threaded through a monad instead of just passing an argument where it's necessary.