Search Haskell Channel Logs

Wednesday, February 1, 2017

#haskell channel featuring orzo, Cale, cocreature, nshepperd_, mbw, jchia_, and 7 others.

nshepperd 2017-01-31 20:45:24
jchia_: 'f <*> g' should always be thought of as 'running' f before g, whenever there's a difference between that and the opposite
nshepperd 2017-01-31 20:45:44
jchia_: but there are applicatives where order doesn't matter
Cale 2017-01-31 20:45:46
You sort of gave an example there -- it would be possible to define a concurrent Applicative instance.
jchia_ 2017-01-31 20:47:24
Let's say i'm making a Monad for expressing reading something from some kind of database system, Haxl being a possible example. I could issue multiple queries in parallel in one batch or sequentially, with one query per batch. The query result is the same but the underlying activity is different. If I use >>=, I issue one query at a time. If I use <*>, I can combine all the terms into one batch query. Does that make sense?
nshepperd 2017-01-31 20:47:24
newtype Par a = Par { getPar :: IO a }
nshepperd 2017-01-31 20:48:12
you could define a 'f <*> g' for that that runs both things simultaneously in two threads, then combines the results
geekosaur 2017-01-31 20:48:25
wasn't someone messing with that a month or so back? (and rediscovered that the overhead swamps the gain in the vast majority of cases)
quchen 2017-01-31 20:49:38
nshepperd: The Concurrently type in Async does exactly that
orzo 2017-01-31 20:50:01
well if the compiler had a super algorithm, it might be able to decide on a per-use bases whether <*> is concurrent
Cale 2017-01-31 20:51:10
Decide?
orzo 2017-01-31 20:51:49
that's the word i used
Cale 2017-01-31 20:52:11
orzo: But the two programs behave differently
mrkgnao 2017-01-31 20:52:15
how do I make a lens that reads a value from a Reader environment?
orzo 2017-01-31 20:52:17
compiler decides to emit concurrent code or sequential code based on some fancy heuristics
Cale 2017-01-31 20:52:18
I don't think you'd want it to decide, generally
orzo 2017-01-31 20:52:53
they both behave the same: with concurrent semantics
kadoban 2017-01-31 20:52:57
Cale: Don't we already let the compiler decide how our programs should run, exactly? I don't get to choose evaluation order.
mrkgnao 2017-01-31 20:52:57
say I wanted to write func i = f . ix i . g, where j has to be read from
Cale 2017-01-31 20:53:00
mrkgnao: I'm not sure what that means. You can use ordinary lenses with asks or local
orzo 2017-01-31 20:53:02
under this hypothetical
mrkgnao 2017-01-31 20:53:02
whoops, sorry
cocreature 2017-01-31 20:53:25
mrkgnao: it can't be a lens because you can't set the value of a reader environment
Cale 2017-01-31 20:53:27
kadoban: That's very different from the order of execution of IO actions
Cale 2017-01-31 20:53:38
kadoban: Every evaluation order will produce the same result
mrkgnao 2017-01-31 20:53:39
say I wanted to write func i = f . ix' i j . g, where ix' i j = ix (i % j) and j has to be read from a reader env
mrkgnao 2017-01-31 20:53:44
can this be done?
Cale 2017-01-31 20:53:46
But executing IO actions in different orders won't.
Gurkenglas 2017-01-31 20:53:51
:t local -- cocreature, you can :/
lambdabot 2017-01-31 20:53:54
MonadReader r m => (r -> r) -> m a -> m a
Cale 2017-01-31 20:53:59
(and will generally look very different to the user of the program)
orzo 2017-01-31 20:54:00
Cale, i mean if we adopted the <*> is concurrent rule, you wouldn't (couldn't) use it to sequence IO actions
orzo 2017-01-31 20:54:12
and then the compiler would be free to decide whether it is actually concurrent
Cale 2017-01-31 20:54:19
Oh, I see what you mean
kadoban 2017-01-31 20:54:29
Cale: But that's precisely why IO's Applicative and Monad agree, right? Because it could give different results if you start messing with that, but aren't we talking about a Monad/Applicative pair where it doesn't particularly matter, except for performance?
mrkgnao 2017-01-31 20:55:07
I tried doing something like func i = do j <- ask; f . ix' i j . g, but it ended badly
cocreature 2017-01-31 20:55:08
Gurkenglas: not really. local requires that you have the rest of your program available. it's not just a single action in the reader monad like setting the value in the state monad is
Cale 2017-01-31 20:55:14
I still don't think I like that very much, but it's debateable I suppose.
Gurkenglas 2017-01-31 20:55:18
mrkgnao, func i = do i <- ask; return $ f . ix (i % j) . g
Cale 2017-01-31 20:55:39
Having the compiler arbitrarily decide that it wasn't going to make your program concurrent despite the fact that you asked for that sounds pretty annoying.
Gurkenglas 2017-01-31 20:55:43
This, of course, places the returned value in the reader context.
Cale 2017-01-31 20:56:17
There won't in general be a way for the compiler to know that sequentialising the actions will meet the requirements of your program
mrkgnao 2017-01-31 20:56:33
Gurkenglas: I was missing the return. :/
Cale 2017-01-31 20:56:38
You might have concerns about the latency of those actions occurring which the concurrency is meant to solve.
nshepperd_ 2017-01-31 20:57:48
Also, preventing deadlock might be incompatible with sequentialising
mrkgnao 2017-01-31 20:58:39
how would I use this like a normal lens that works in a State context?
Cale 2017-01-31 20:58:46
nshepperd: Yeah, if it didn't involve solving the halting problem, you could almost imagine a sufficiently smart compiler checking for that
mrkgnao 2017-01-31 20:59:35
I don't want to have to >>= everywhere if I can help it
Cale 2017-01-31 20:59:56
mrkgnao: Lenses don't normally have anything to do with Reader or State
mrkgnao 2017-01-31 21:00:16
well, I mean, .= is a nice example of what I'm going for
mrkgnao 2017-01-31 21:00:28
is anything along those lines possible?
orzo 2017-01-31 21:00:29
:t (.=)
lambdabot 2017-01-31 21:00:33
MonadState s m => ASetter s s a b -> b -> m ()
Cale 2017-01-31 21:00:58
ah, I don't use any of that stuff. You certainly can't .= from a Reader, since the operation simply doesn't make sense.
Cale 2017-01-31 21:01:16
But you can asks (view l)
Cale 2017-01-31 21:01:48
Where l is a lens from your Reader's environment to some part of it.
mrkgnao 2017-01-31 21:02:25
would moving the reader into the State portion of my stack help?
Cale 2017-01-31 21:02:47
It would help if you want to be able to update the environment somehow
Cale 2017-01-31 21:03:01
(but that has nothing to do with lens)
mrkgnao 2017-01-31 21:03:23
no, I mean, for unobtrusive use with (.=)
Cale 2017-01-31 21:03:45
.= doesn't make any sense as an operation for an environment that is read-only
Cale 2017-01-31 21:04:24
right?
nshepperd_ 2017-01-31 21:04:39
view :: Lens' s a -> Reader s a -- iirc can be used directly in a reader context
Cale 2017-01-31 21:05:28
ah, right, it can
Cale 2017-01-31 21:05:34
because of typeclass magic
nshepperd_ 2017-01-31 21:05:52
do x <- view (foo . bar)
Cale 2017-01-31 21:06:46
Lens is full of stuff that's way below the Fairbairn threshold ;)
Gurkenglas 2017-01-31 21:07:07
mrkgnao, func i = asks $ \j -> f . ix (i % j) . g
nshepperd_ 2017-01-31 21:07:22
btw 'use' is the same thing but for state
mrkgnao 2017-01-31 21:10:08
but I still need to use <- or >>= to "get" the lens out, which makes sense, but is there a way around that?
Cale 2017-01-31 21:10:54
mrkgnao: Gurkenglas' example just now didn't use >>=
mrkgnao 2017-01-31 21:12:14
Cale: I'd like to do something like func i .= someValue
Cale 2017-01-31 21:12:28
huh?
Cale 2017-01-31 21:12:46
I'm confused, what operation are you actually trying to perform
mrkgnao 2017-01-31 21:12:50
using his example, what I have to do is f <- func i; f .= someValue
Cale 2017-01-31 21:13:08
Can you write it entirely without lens, and then maybe we'll consider whether it's worth doing something involving lens?
mrkgnao 2017-01-31 21:13:18
okay.
Cale 2017-01-31 21:13:48
Oh, you want a variant of .= which gets the value to set the thing to from another action?
mrkgnao 2017-01-31 21:14:02
I have some State that includes a vector, and I need to index into the vector, but allow wrapping around the end (by mod-ing by the length)
mrkgnao 2017-01-31 21:14:44
now the length is stored in the Reader part of my monad stack, which has a Settings type (and the length doesn't change)
mrkgnao 2017-01-31 21:15:00
I'd like a lens to index into the vector, but in the way I mentioned
Cale 2017-01-31 21:15:54
I probably wouldn't bother using lens for this. I would simply define a function which asks for the appropriate setting, then extracts the Vector from the state, and simply indexes it in the normal way
kadoban 2017-01-31 21:16:02
Probably a side-note, but doesn't a vector know it's own length?
cocreature 2017-01-31 21:16:11
kadoban: yep it does
Cale 2017-01-31 21:16:14
and then use that
mrkgnao 2017-01-31 21:16:27
I think it does, but now I sort of want to see if what I'm trying is possible
Cale 2017-01-31 21:16:57
In fact, given that you need to guarantee that the index is modded out by the appropriate value, I would question slightly whether you *really* want the MonadState instance.
cocreature 2017-01-31 21:16:59
it is very easy to find yourself in a position where you are trying to solve a problem using lens that is really a lot easier to solve without it
mrkgnao 2017-01-31 21:17:11
but I think there isn't a way to have an environment-dependent lens do the reading of the environment "silently"
mrkgnao 2017-01-31 21:17:47
Cale: my vector is being modified. how am I supposed to work with that without State?
Cale 2017-01-31 21:17:52
It might be better (safer) to define your own type class, and newtype your monad in such a way that the user doesn't have direct access to the state, but instead only accesses it via operations which do that bit of arithmetic for you.
mrkgnao 2017-01-31 21:17:54
(sorry if that came across badly)
cocreature 2017-01-31 21:18:15
mrkgnao: that's not specific to lens. if you want to read the value from your environment, you need to have a monadic action. lens can't work around that
mrkgnao 2017-01-31 21:18:47
I think I see what you're saying
Cale 2017-01-31 21:19:21
(or even don't define the type class, and just write the operations for the newtype)
Cale 2017-01-31 21:19:30
(but people like different styles there)
cocreature 2017-01-31 21:19:45
mrkgnao: also instead of wrapping a vector in State, you might want to consider a mutable vector
Cale 2017-01-31 21:19:47
Depends how aggressively you're using monad transformers
mrkgnao 2017-01-31 21:19:54
but the thing is, the elements of the vector are themselves sort of deeply nested things that lens is helping a lot with
Cale 2017-01-31 21:19:56
Oh, that too.
Cale 2017-01-31 21:20:19
Well, that's fair enough.
Cale 2017-01-31 21:20:36
You can still use lens in places where it makes a lot of sense to do that.
mrkgnao 2017-01-31 21:21:43
the existence of %= as a nice way to do modify $ over thing func was what convinced me that this, too, would be possible to do
mbw 2017-01-31 21:22:22
How can I find out what kind of exception can be thrown by a specific partial function, say for instance Data.List.head or Data.Vector.head? If I wanted to handle this kind of error, my error handling code should refer to something more specific than IOException or SomeException, no?
Cale 2017-01-31 21:22:47
I would also usually write modify (over l f), just because I rather dislike the proliferation of infix shenanigans in lens -- it can get hard to remember what all that stuff is actually doing.
cocreature 2017-01-31 21:22:51
mbw: you can't find out the exceptions that can be thrown without inspecting the source code
mbw 2017-01-31 21:23:26
So, SomeException it is?
mbw 2017-01-31 21:23:58
I know I should probably prefer making functions total, but still, it feels kind of weird.
Cale 2017-01-31 21:24:08
mbw: The exceptions thrown by those two aren't really the sort which it makes much sense to try to catch
Cale 2017-01-31 21:24:36
This is because they occur during expression evaluation, rather than as part of the execution of an IO action
Cale 2017-01-31 21:25:10
So you have to be very careful about that. Control.Exception.evaluate can help, but catching this sort of exception is sort of a last resort.
cocreature 2017-01-31 21:25:14
> catch (error "hi") $ \(SomeException e) -> print (typeOf e)
lambdabot 2017-01-31 21:25:18
cocreature 2017-01-31 21:25:21
gnah
Cale 2017-01-31 21:25:40
If something uses 'error' or 'throw', rather than 'throwIO' to throw an exception, that exception is not really meant to be caught.
cocreature 2017-01-31 21:25:43
mbw: you can use something like the above to figure out the type of the exception that you want to catch
mbw 2017-01-31 21:25:53
> catch (head []) $ \(SomeException e) -> print (typeOf e)
lambdabot 2017-01-31 21:25:56
cocreature 2017-01-31 21:26:11
mbw: try it in GHCi, lambdabot is not helpful here
Cale 2017-01-31 21:26:14
lambdabot won't execute IO actions
mbw 2017-01-31 21:26:25
Ah, ok.
Cale 2017-01-31 21:26:37
The type in this case is ErrorCall
cocreature 2017-01-31 21:26:44
but Cale is right, catching the exception thrown by "error" is rarely useful
cocreature 2017-01-31 21:27:10
if you can handle the exception thrown by "head" just pattern match on it
cocreature 2017-01-31 21:27:21
and if you can't handle it, then just let it crash
Cale 2017-01-31 21:27:28
Yeah, you should just assume that it is your obligation to ensure that any function which uses 'error' is applied in such a way that it doesn't actually use it.
Cale 2017-01-31 21:28:16
and yeah, if you're checking that the list is nonempty, and then using head and/or tail, you should just have been pattern matching in the first place
mbw 2017-01-31 21:30:19
I wasn't referring to a specific example I am dealing with right now. I'm not a great fan of exceptions, *especially* after coming to appreciate total functions.
Cale 2017-01-31 21:31:32
Generally, I pretend that anything which uses 'error' or 'throw' rather than 'throwIO' is just doing me the favour of killing the entire program quickly rather than looping forever.
mrkgnao 2017-01-31 21:31:40
is there a way to "combine" lenses outside of simply sequentially composing them?
Cale 2017-01-31 21:31:55
mrkgnao: There are dozens of ways...
Cale 2017-01-31 21:32:13
But what are you trying to accomplish?
mrkgnao 2017-01-31 21:33:07
Well, I have a lens that gives me the length of my vector. And I have the lens that indexes into the vector and pulls something out of the data at that index.
mrkgnao 2017-01-31 21:33:52
Now I want to combine the two, so that the indexing can wrap around like I said above.
mbw 2017-01-31 21:33:55
So, error should be used for the "the impossible happened" kind of messages? What's the difference between throw and throwIO, if I might ask?
Cale 2017-01-31 21:34:09
:t throwIO
lambdabot 2017-01-31 21:34:11
Exception e => e -> IO a
Cale 2017-01-31 21:34:14
:t throw
lambdabot 2017-01-31 21:34:15
Exception e => e -> a
Cale 2017-01-31 21:34:35
throwIO gives you an action which, when executed, causes the given exception to be raised
Cale 2017-01-31 21:34:55
throw gives you a value of an arbitrary type which, when *evaluated*, causes the given exception to be raised
Cale 2017-01-31 21:35:18
Evaluating throwIO x won't generally do anything visible.
mbw 2017-01-31 21:35:24
These type signatures look highly suspicious...
Cale 2017-01-31 21:35:26
Only executing it will
Cale 2017-01-31 21:35:37
What about them?
Cale 2017-01-31 21:35:47
The 'a'?
mbw 2017-01-31 21:36:00
if I didn't know anything about it, it would look like a coercion
Cale 2017-01-31 21:36:18
The 'a' there is a way of cluing you in to the fact that these things don't actually produce a result.
mbw 2017-01-31 21:36:40
Like in absurd?
Cale 2017-01-31 21:36:44
yeah
mrkgnao 2017-01-31 21:36:47
Cale: any ideas?
Cale 2017-01-31 21:36:52
Because it's a value of an arbitrary type completely unrelated to anything that was given as input
Cale 2017-01-31 21:37:18
mrkgnao: I would just write the function and use it, rather than worrying about finding something in Control.Lens.* which does that exact thing.
mbw 2017-01-31 21:38:06
So I use throw or throwIO depending on when the function I'm in needs to typecheck via returning an action or a value?
mbw 2017-01-31 21:38:17
*f
mrkgnao 2017-01-31 21:38:18
well, I'm not sure how to write it. I need a lens that does that (otherwise I'll have to change a lot of code that I'd prefer not to)
mbw 2017-01-31 21:38:19
*if
Cale 2017-01-31 21:38:23
mbw: No...
mbw 2017-01-31 21:38:27
Sorry :(
Cale 2017-01-31 21:38:56
You use throwIO in any case where you intend that someone might want to catch the exception.
Cale 2017-01-31 21:39:17
and throwing the exception has to occur as part of an IO action in that case
Cale 2017-01-31 21:39:40
It'll only happen when the action gets *run*, not when it's merely evaluated for some reason
Cale 2017-01-31 21:40:07
I suppose I should check that you're familiar with the distinction we make between evaluation and execution?
mbw 2017-01-31 21:40:30
You're right, I'm not sure I am at this point.
Cale 2017-01-31 21:41:03
Evaluation refers to rewriting (representations of) expressions at runtime into values, according to the definitions in your program. It's generally done in order to be able to pattern match.
Cale 2017-01-31 21:41:27
It generally has no user-visible effects, apart from making your CPU warm
Cale 2017-01-31 21:42:04
Execution of an IO action means carrying out the steps that it describes.
Cale 2017-01-31 21:42:19
It can have any effect that your computer is capable of producing.
Cale 2017-01-31 21:43:03
So when you *evaluate* an IO action, not a whole lot happens, apart from putting it into some internal representation where the machine will be ready to execute it.
mbw 2017-01-31 21:43:05
So I could evaluate a monadic action to head normal form without producing the effects captured by the monad?
Cale 2017-01-31 21:43:27
Yeah, specifically with IO
Cale 2017-01-31 21:43:58
But in general, you'll have some either weird notion of what it means to execute actions in your monad, and it won't coincide with evaluation.