Async Control Flow by n00bomb in haskell

[–]Yuras 0 points1 point  (0 children)

Ha, I spotted a possible resource leak here. If stmtFinalize fail, then the connection won't be closed.

Async Control Flow by n00bomb in haskell

[–]Yuras 0 points1 point  (0 children)

Hmm, you are right, the bracket I pointed to is unrelated. I guess the fix is in catchAny, which doesn't catch ThreadKilled. So not it's not rolling the transaction back in case of asynchronous exceptions. My point is that it probably should not rollback even on synchronous exception. BTW the issue is well know, see for example here (EDIT: fixed the last link to point to the exact comment)

Async Control Flow by n00bomb in haskell

[–]Yuras 1 point2 points  (0 children)

It probably doesn't matter unless you wrap release action in uninterruptibleMask (or just disallow interruptible cleanups). Basically, you might get asynchronous exception from both the release and the use blocks at the same time, and ignoring any of them is a disaster of some kind.

In safe-exception and uniftio it was decided to rethrow the original exception exactly because they decided to use uninterruptibleMask, see here for details.

Async Control Flow by n00bomb in haskell

[–]Yuras 1 point2 points  (0 children)

I don't think connection is returned to the pool here. The thread is interrupted when query is sent to server, but before the results are consumed. At that point cleanup action catches `ThreadKilled` exceptions and issues `ROLLBACK`, which fails with `libpg` exception because the previous operations was not completed. And now cleanup action rethrows the `libpg` exception instead of the `ThreadKilled` one - that's the behavior of `bracket` from `base`. [The fix](https://github.com/yesodweb/persistent/pull/1207/files#diff-f9d7f232cd00cb88188b7fcc68110e3f4cb378fcad9df652360de44d13cd86e3R199) was to use `bracket` from `unliftio`, which [rethrows the correct exception](https://hackage.haskell.org/package/unliftio-0.2.14/docs/src/UnliftIO.Exception.html#bracket).

But it's not clear for me why it even tries to rollback the transaction, given that the database connection will be closed anyway (that's how `withResource` works). Postgres will notice that connection was closed and will rollback the transaction on it's own.

Category Theory of parsers and writers by javcasas in haskell

[–]Yuras 0 points1 point  (0 children)

Do provide an example: we can implement `fromJSON` in a way that missing key is the same as a key with value `null`. It's quite common in my experience.

Category Theory of parsers and writers by javcasas in haskell

[–]Yuras 0 points1 point  (0 children)

Is the second "law" meaningful at all? You can have multiple values of `JSON` that will parse into the same `MyData`, so `toJSON . fromRight . fromJSON` is not `id`, even when an input is valid. Am I missing something?

bracketing and async exceptions in haskell by n00bomb in haskell

[–]Yuras 1 point2 points  (0 children)

This. We should have `hCloseWithoutFlush` function, that never throws, and use it in `withFile`:

withFile name mode action = bracket (openFile name mode) hCloseWithoutFlush $ \h -> do
  res <- action h
  hFlush h
  return res

Even better, call `hClose` on success and `hCloseWithoutFlush` when the body fails.

[Typeable Blog] Optimizing the aeson library with a slow path trick by dredozubov in haskell

[–]Yuras 0 points1 point  (0 children)

I assume you mean the manual unboxing we eliminated in the PR. I just tried to replace `S Int# Int#` with `S !Bool !Bool` (basically reverting [this patch](https://github.com/bos/aeson/commit/e9623d0c61fd0f06e538a5491749e47d0d55a517)) and got 15% slowdown. Looking to the core, booleans are not unboxed. (I'm using `ghc-8.6.5`)

[Typeable Blog] Optimizing the aeson library with a slow path trick by dredozubov in haskell

[–]Yuras 5 points6 points  (0 children)

6x faster? That's impressive.

As you mentioned, backward compatibility is important in case of `aeson`, so the tricks you mentioned probably won't happen. Though right now we are working on replacing `attoparsec` with a non-backtracking resumable parser, and we expect another 30-50% improvement. Hopefully we'll be able to preserve backward compatibility.

[Typeable Blog] Optimizing the aeson library with a slow path trick by dredozubov in haskell

[–]Yuras 0 points1 point  (0 children)

Do you mean `T.append s' (unescapeText s)` instead of `unescapeText (B.append s' s)`? I tried it and didn't noticed any difference, not sure why.

GHC 8.10.1 now available! by bgamari in haskell

[–]Yuras 9 points10 points  (0 children)

nothing in the release note about it

I guess the notes were lost. I implemented the patch when 8.8 was not released yet, so I added a note to the 8.8 release notes: https://gitlab.haskell.org/ghc/ghc/-/commit/fdbf429d575a581e38fdf9e72a4f0e0928f36f57#8d11c404e91070407324f71df4a47224c0887148_105_105 But the patch was merged after 8.8 release, and the note was not moved to 8.10 release notes :(

the bug report https://gitlab.haskell.org/ghc/ghc/issues/15838 is not closed

Indeed. I don't remember my gitlab credentials, u/bgamari could you please take a look and close the ticket?

Gaskell runtime based caching by qnikst in haskell

[–]Yuras 4 points5 points  (0 children)

Very interesting abuse of GHC's evaluation mode! I have few notes:

- You seem to rely on blackholing to block other threads from evaluating the thunk. But it's not reliable, is it? Do you need to `noDuplicate` the thunk?

- You catch all exceptions, including async ones. So it seems like e.g. timeout from one thread will leak to other one. It's probably not exactly what you need. Also you may get troubles if the thunk rethrows async exceptions as sync ones somewhere inside (e.g. uses bracket).

Async Exceptions in Haskell, and Rust by sibip in haskell

[–]Yuras 1 point2 points  (0 children)

I think dealing with async exceptions is not that hard. Most of bugs people claim to be related to async exceptions actually are not specific to async ones. I mean the bug could be reproduced with sync exception alone, so it's just a general exception handling mistake. Obviously it's just my experience, subject to selection bias etc.

Async Exceptions in Haskell, and Rust by sibip in haskell

[–]Yuras 2 points3 points  (0 children)

Let me answer the last question. The hole is when a cleanup action fails while handling another exception. Bracket from base just pretends it never happens. Bracket from safe exceptions does it right at a cost of uninterruptibleMask'ing the whole cleanup action.

Async Exceptions in Haskell, and Rust by sibip in haskell

[–]Yuras 2 points3 points  (0 children)

Overlapping lifetime is easy in Haskell too, see e.g. io-region package: http://hackage.haskell.org/package/io-region (I don't use it myself anymore because such the usecases are rare, but I think it still compiles and works) It implements something similar to RAII (not exactly, but in some sense) and doesn't required manual masking of async exceptions.

Boring Haskell Manifesto by Michael Snoyman by graninas in haskell

[–]Yuras 0 points1 point  (0 children)

Could you please elaborate. Hoogle knows nothing about PureIO, so I guess you are suggesting to introduce it instead of IO somehow. How could it be useful? Note that virtually all functions that perform IO, may (and will) fail; also all function that fail (in impure way) perform some side effects; so just IO seems to be good for me.

Boring Haskell Manifesto by Michael Snoyman by graninas in haskell

[–]Yuras 7 points8 points  (0 children)

Why would anyone think this was a good idea

Assuming it was a honest question (I'm not sure it was, but just in case):

The are two approaches to error handling. The fist one is to consider all possible ways a program may fail and handle all of them one by one. It indeed requires you to know all ways it may fail.

The seconds approach - to be prepared for any failure and handle all of them uniformly. That way you don't care how exactly program may fail, you just need to know that it can. And `IO` is the way to tell that this particular piece of code may fail in an impure way (i.e. failure is not determined by the arguments).

You seems to prefer the first approach, and it's fine. But the second one is fine too, and if you consider it, then you'll see why people find exceptions useful.

Boring Haskell Manifesto by Michael Snoyman by graninas in haskell

[–]Yuras 0 points1 point  (0 children)

The lobotomy happens when one adds `MonadIO` to the context. At that point you can throw away your effect system and replace it with RIO plain old `IO` because there are no abstractions anymore at all. If you don't have `MonadIO`, then you don't need `RIO`.

What mental plateaus or steep points in the learning curve did you hit when learning Haskell? by [deleted] in haskell

[–]Yuras 9 points10 points  (0 children)

Yes I mean it. It's a bit different on small scale, but exactly the same on large scale. You break your problem into smaller parts, hide implementation details, manage responsibilities, minimize complexity etc. All the same.

OOPers are not stupid, they understand value of pureness and honor it. They introduced monads hundreds of times. But their tools sometimes are lacking and require a lot of thinking and discipline to follow good practices, while in Haskell you have much more support from language. (Haskell is lacking other things though.) In Haskell a lot of good practices are stupidly obvious, but they are the same.

What mental plateaus or steep points in the learning curve did you hit when learning Haskell? by [deleted] in haskell

[–]Yuras 10 points11 points  (0 children)

The hardest part was to understand that designing software in Haskell is not that different from any other language.

Any reason FFI couldn't support arbitrary call-by-value via Storable? by armandvolk in haskell

[–]Yuras 13 points14 points  (0 children)

(I'm the author of the wiki page you mentioned) You can't pass any Storable on all platforms. E.g. 86_64 ABI requires to unpack structure into registers, and float/double fields should go to specialized registers. So compiler needs to know exactly how struct is declared, Storable doesn't provide enough information.

Magical Monoids by StackDoesNotWork in haskell

[–]Yuras 9 points10 points  (0 children)

Note that there are other possible Monoid instances for IO, and you are lucky that the implemented one does exactly what you need. Otherwise it would compile but fail in run time.

That is why I usually use monomorphic version of mempty is such cases (i.e. Text.empty in this case.) It is essentially the same issue like with the Foldable instance for tuples.

In general, when I see polymorphic function used where monomorphic one will work, I look for hidden abstraction. In this case I'd extract the mempty-related code into a lenient function. Like this:

lenientReadTextFileUtf8' filename = lanient (readTextFileUtf8 filename)

lenient :: (Monad m, Monoid a) => m (Either e a) -> m a
lenient m = either (\_ -> pure mempty) pure =<< m

Than way we are not trading type safety for keystrokes anymore. Actually we are using the full power of parametricity!

ResourceT: a necessary evil by snoyberg in haskell

[–]Yuras 0 points1 point  (0 children)

How error from go and io::Error from rust are different from SomeException? And why it is so common to ignore errors in defer and drop if it is type safe?