Search Haskell Channel Logs

Tuesday, January 31, 2017

#haskell channel featuring quchen, ertes, orion, lambdabot, puregreen, merijn, and 6 others.

roxxik 2017-01-31 01:45:25
the ordering of what?
roxxik 2017-01-31 01:45:34
what is the effect here?
ski 2017-01-31 01:45:46
the ordering of the action `forEach ...' wrt the action `forSome ...'
roxxik 2017-01-31 01:45:53
hmmm
ski 2017-01-31 01:45:56
the effect in this particular case is quantification
alexv19 2017-01-31 01:46:25
How is this module supposed to be used http://hackage.haskell.org/package/constraints-0.9/docs/Data-Constraint-Deferrable.html ? Can I use it to check if some instance is defined?
ski 2017-01-31 01:47:18
"Every pot has a lid." could be interpreted as saying that for each pot, there is a corresponding lid (which lid you take presumably depends on the pot chosen). or as saying that there is a lid which fits on every pot
ski 2017-01-31 01:47:40
in this particular example, the first reading would be the intended one
ski 2017-01-31 01:49:06
> (,) [0,1,2] `ap` "ab"
lambdabot 2017-01-31 01:49:08
error:
lambdabot 2017-01-31 01:49:08
• Couldn't match expected type '[Char -> b]'
lambdabot 2017-01-31 01:49:09
with actual type 'b0 -> ([Integer], b0)'
ski 2017-01-31 01:49:19
> (,) <$> [0,1,2] `ap` "ab"
lambdabot 2017-01-31 01:49:22
error:
lambdabot 2017-01-31 01:49:22
• No instance for (Typeable a0)
lambdabot 2017-01-31 01:49:22
arising from a use of 'show_M15407747453764654999268'
roxxik 2017-01-31 01:49:39
> ((,) <$> [0,1,2]) `ap` "ab"
lambdabot 2017-01-31 01:49:44
[(0,'a'),(0,'b'),(1,'a'),(1,'b'),(2,'a'),(2,'b')]
ski 2017-01-31 01:49:59
oh, brackets
ski 2017-01-31 01:50:09
> ((,) <$> [0,1,2]) `altAp` "ab"
lambdabot 2017-01-31 01:50:12
error:
lambdabot 2017-01-31 01:50:12
• Couldn't match type '[]' with 'ContT r Identity'
lambdabot 2017-01-31 01:50:12
Expected type: Cont r (t -> (a, t))
roxxik 2017-01-31 01:50:14
:t altAp
lambdabot 2017-01-31 01:50:16
Cont r (t -> a) -> Cont r t -> Cont r a
ski 2017-01-31 01:50:21
yeah, right
ski 2017-01-31 01:50:47
@let iab `pa` ia = flip ($) <$> ia <*> iab
lambdabot 2017-01-31 01:50:49
Defined.
ski 2017-01-31 01:50:54
> ((,) <$> [0,1,2]) `pa` "ab"
lambdabot 2017-01-31 01:50:56
[(0,'a'),(1,'a'),(2,'a'),(0,'b'),(1,'b'),(2,'b')]
ski 2017-01-31 01:51:31
in this case, the ordering of the actions in the list monad corresponds to "nesting" (outer "loop" vs. inner "loop")
roxxik 2017-01-31 01:51:41
i see
ski 2017-01-31 01:52:05
something similar, iow nesting, holds for the `Cont' case
roxxik 2017-01-31 01:53:19
so pa will behave the same for Maybe?
roxxik 2017-01-31 01:53:23
(as ap)
ski 2017-01-31 01:54:01
yes, since ordering doesn't matter there (at least if we ignore bottoms)
ski 2017-01-31 01:54:14
hm, actually ..
ski 2017-01-31 01:54:17
@type (<**>)
lambdabot 2017-01-31 01:54:19
Applicative f => f a -> f (a -> b) -> f b
ski 2017-01-31 01:54:22
is `pa'
ski 2017-01-31 01:54:35
(hm, well almost, it's `flip pa')
roxxik 2017-01-31 01:54:54
((,) <$> [0,1,2]) (flip <**>) "ab"
roxxik 2017-01-31 01:55:02
> ((,) <$> [0,1,2]) (flip (<**>)) "ab"
lambdabot 2017-01-31 01:55:05
error:
lambdabot 2017-01-31 01:55:05
• Couldn't match expected type '(f0 (a0 -> b1) -> f0 a0 -> f0 b1)
lambdabot 2017-01-31 01:55:05
-> [Char] -> t'
roxxik 2017-01-31 01:55:28
> (flip (<**>)) ((,) <$> [0,1,2]) "ab"
lambdabot 2017-01-31 01:55:31
[(0,'a'),(1,'a'),(2,'a'),(0,'b'),(1,'b'),(2,'b')]
roxxik 2017-01-31 01:55:39
ah ok
ski 2017-01-31 01:57:31
so `(<*>)' and `(<**>)' execute the actions in the visual order given (the second of them taking the function-yielding action after instead of before), while `pa'/`flip (<**>)' takes arguments of the same types as `(<*>)', but reverses the execution order to the reverse of the visual order
ski 2017-01-31 01:58:31
which makes sense, i think. i think it'd normally be more sensible to stick within a context to a single execution order, and then use `(<**>)' if you want the function-yielding action to be executed afterwards
roxxik 2017-01-31 01:59:36
ah now i see a bit clearer, i can define the evaluation order of effects in an applicative
ski 2017-01-31 01:59:50
s/evaluation/execution/
roxxik 2017-01-31 02:00:09
where f <$> a <*> b will evaluate a's effect first and b's second f <$> a <**> b will do it the other way around
roxxik 2017-01-31 02:00:22
ok execution order
ski 2017-01-31 02:00:42
for some idioms (`Maybe',`Reader r'), the execution order doesn't actually matter, but for some other idioms (`Writer w',`State s',`[]',`Cont o') it does matter
ski 2017-01-31 02:01:24
`f <$> a <**> b' will still execute the effect of `a' before the effect of `b'
roxxik 2017-01-31 02:01:24
i'd still need to know the effect of cont... it always confuses me :(
merijn 2017-01-31 02:01:32
roxxik: Feeling confused about Cont is normal :)
roxxik 2017-01-31 02:01:46
ski: shouldn't be
ski 2017-01-31 02:01:58
(or, stated another way : the compound/composite action will have effects composed from the effects of `a' before the effects of `b')
roxxik 2017-01-31 02:02:24
merijn: what's Cont actually useful for? haven't seen it in the wild
merijn 2017-01-31 02:02:39
roxxik: ContT is nice for capturing the pattern of nested brackets
ski 2017-01-31 02:03:09
`(<*>)' is `liftA2 ($)', while `(<**>)' is `liftA2 (flip ($))', the only difference is the result types of the two actions, and how we combine the two resulting values. the execution order of the arguments is the same
merijn 2017-01-31 02:03:13
roxxik: This has a nice example: https://stackoverflow.com/questions/26436095/what-are-good-haskell-conventions-for-managing-deeply-nested-bracket-patterns
roxxik 2017-01-31 02:03:14
merijn: and where does that happen
merijn 2017-01-31 02:03:33
roxxik: When dealing with resource allocation/freeing (like opening files, FFI, etc.)
roxxik 2017-01-31 02:03:44
hmm ok
merijn 2017-01-31 02:04:14
roxxik: See also Tekmo's 'managed' package
roxxik 2017-01-31 02:04:29
ski: b <**> (f <$> a) i flipped the type D:
merijn 2017-01-31 02:04:52
roxxik: https://hackage.haskell.org/package/managed-1.0.0/docs/Control-Monad-Managed.html <- this is basically a version of ContT
merijn 2017-01-31 02:05:19
ertes: Perhaps, but I doubt anyone will argue that that's more beginners friendly than Managed :p
merijn 2017-01-31 02:06:24
ertes: Because I still don't understand wtf kan extensions are
ertes 2017-01-31 02:06:27
merijn: you're underestimating beginners =)
merijn 2017-01-31 02:06:39
ertes: And Codensity (to me) is still just "DList generalised"
ertes 2017-01-31 02:06:42
merijn: me neither, but i can use Codensity anyway =)
ski 2017-01-31 02:07:48
merijn : that's funny, since i think of `DList' as a specialized version of continuation stuff :)
roxxik 2017-01-31 02:08:37
merijn: so nesting callbacks is the usecase of Cont?
merijn 2017-01-31 02:08:49
ski: I learned and understood DList first and then looked at Codensity (before it was called that) and went like "I'm thoroughly confused" and had the epiphany "this is just DList, but more general"
merijn 2017-01-31 02:09:27
roxxik: Cont can be used to use callbacks while writing "imperative/non-callback code"
ski 2017-01-31 02:11:08
Kan extensions are adjoints of precomposition functors (of the shape `(. g)', for some functor `g') ..
merijn 2017-01-31 02:11:42
I don't understand what adjoints are either :p
merijn 2017-01-31 02:11:52
Or wtf precomposition functor means, for that matter :p
roxxik 2017-01-31 02:11:56
(how do i so this * thing)? * roxxik still wonders what adjoints are
ertes 2017-01-31 02:11:59
roxxik: one way to use ContT is to "register" actions to be run after the whole ContT action
ertes 2017-01-31 02:12:54
roxxik: ContT (\k -> k 5) -- this is a ContT action that does nothing and returns 5 (by calling the continuation with 5)
merijn 2017-01-31 02:13:08
roxxik: "/me "
ski 2017-01-31 02:13:10
if `g' is a functor from `C' to `D', then the precomposition with `g', `(. g)', is a functor from `E^D' to `E^C' (or from `D -> E' to `C -> E', if you prefer)
ertes 2017-01-31 02:13:16
roxxik: now that 'k' is "the rest of the ContT action"
ertes 2017-01-31 02:13:39
roxxik: ContT (\k -> k () `finally` putStrLn "Ok, done.") -- so you can do this
roxxik 2017-01-31 02:13:53
those category things look like the functor instance for (->)
ski 2017-01-31 02:13:58
given any object in `E^D', which is a functor, say `f', from `D' to `E', it precomposes `f' with `g', iow `f . g' (so `g' "modifes" the input before it's passed to `f')
ski 2017-01-31 02:14:13
and that is a functor from `C' to `E', iow an object in `E^C'
merijn 2017-01-31 02:14:21
roxxik: If you're interested in Category Theory, have you seen Bartosz' blog series on it?
c_wraith 2017-01-31 02:14:34
roxxik: in that category (.) is standard function (.), which is also fmap for Functions, sure. :)
merijn 2017-01-31 02:14:51
roxxik: https://bartoszmilewski.com/2014/10/28/category-theory-for-programmers-the-preface/
ski 2017-01-31 02:14:55
roxxik : i used `ContT' once to do cooperative multi-tasking
roxxik 2017-01-31 02:14:58
merijn: i' read some bits of it but as i arrived at adjoints i was already a little confused
ski 2017-01-31 02:15:19
merijn : makes any sense ?
roxxik 2017-01-31 02:15:43
so (. g) is a functor functor?
ertes 2017-01-31 02:15:52
roxxik: this is of course only one use case for ContT (and better handled by Codensity), but there are many other use cases… sometimes it's used to provide an escape hatch out of a 'forever'
merijn 2017-01-31 02:15:57
ski: Honestly, not really :) Too abstract for me :)
orion 2017-01-31 02:16:27
What functions should I consider if I want to write an application which can load/execute other haskell shared libraries at runtime, given some "Plugin" typeclass?
roxxik 2017-01-31 02:16:45
ertes: sounds like this is needed for the more complex control flow, that i hadn't any need of yet
ertes 2017-01-31 02:17:00
roxxik: it's never *needed*, but sometimes it's convenient
ertes 2017-01-31 02:17:53
roxxik: remember that ContT is just a layer over regular functions… anything you can implement with ContT can also be implemented without it
ertes 2017-01-31 02:18:42
just like ReaderT, which is also a layer around functions, except that ReaderT is never useful =)
ski 2017-01-31 02:19:09
merijn : if we have `foo :: forall a. F (G a) -> H a', a function that somehow traverses an `F' structure, with `G' structures inside, and produces an `H' structure as result, then by using a right Kan extension (`Ran'), we can "view" this as `toRan foo :: forall b. F b -> (Ran G) H b'. so now we appear to only be working on an `F' structure, and we've "instrumented" the outputted `H' structure with a `Ran G' annotation, meaning that eventually, the `b' ele
ski 2017-01-31 02:19:27
cut off near ".., and we've "instrumented" the outputted `H' structure with a `Ran G' annotation, meaning that eventually, the `b' elements should be (or be converted to) `G' structures of `a'"
merijn 2017-01-31 02:19:42
ski: My problem is that I need to generalise from concrete examples and CT is horrible for generalising from concrete examples :)
ski 2017-01-31 02:21:10
merijn : so, in a sense, by using `toRan', we've "curried" the formulation `(F . G) >---> H' into `F >---> (G -> H)', where `G -> H' here is the `(Ran G) H' above, and `>--->' is just "natural transformation", defined as `type NT f g = forall a. f a -> g a' (sometimes written as `~>', infix)
roxxik 2017-01-31 02:21:41
so Ran g h = g ~> h?
ertes 2017-01-31 02:21:56
merijn: if you want a less abstract explanation, just stare at the types from kan-extensions for five minutes
ski 2017-01-31 02:22:00
no, `blah >---> bleh' in my notation is `blah ~> bleh' in some other notation
ertes 2017-01-31 02:22:48
under all the CT terminology they are really useful *tools*
ski 2017-01-31 02:22:53
`(Ran g h) b' is in fact implemented as `forall a. (a -> g b) -> h b' .. but i'm not sure how much that helps
roxxik 2017-01-31 02:23:05
this looks like the laws of basic currying on a functor level
merijn 2017-01-31 02:23:42
ertes: Probably, but they're not tools I have much use for at this exact time and I don't have the time to invest in my free time to learn more :)
ski 2017-01-31 02:23:47
we've curried the transformation from a `G's-nested-inside-`F' structure to an `H' structure, to one which first only sees the `F' structure, and only after that gets to see the "inner" `G' structure
ertes 2017-01-31 02:23:59
merijn: Coyoneda TVar -- TVar with a functor interface =)
ski 2017-01-31 02:24:06
possibly this could be useful if the transformation can do useful work while only seeing `F'
ski 2017-01-31 02:25:06
(cf. defining `frob :: A -> (B -> C)', that analyzes `A' completely (usually recursively), before generating the function from `B' to `C'. e.g. `A' could be a description of a regular expression, and `frob' "compiles" it into a matcher)
roxxik 2017-01-31 02:25:10
ertes: but you need a Functor instance to lower it... how do you then use a Coyoneda TVar?
ski 2017-01-31 02:25:28
ertes : but `Yoneda' also adds a functor instance :)
ertes 2017-01-31 02:25:29
roxxik: you just pattern-match on it
roxxik 2017-01-31 02:25:33
oh
mutsig 2017-01-31 02:25:41
Does anyone have a good 'rule-of-thumb' of when to use Lazy Text vs Text?
ski 2017-01-31 02:25:50
roxxik : "this looks like the laws of basic currying on a functor level" -- exactly
ski 2017-01-31 02:26:18
roxxik : however, what the ramifications of this would be in practice, i'm not fully sure of, yet
roxxik 2017-01-31 02:26:48
ertes: Coyoneda just stores all the fmapped functions and won't apply them? i need to have a look at the implementation
ski 2017-01-31 02:27:07
yep
ski 2017-01-31 02:27:34
it'll leave to you how to actually get your `a' "out" of your `TVar a'
ertes 2017-01-31 02:27:40
mutsig: if in doubt lazy Text acts very much like an efficient String
roxxik 2017-01-31 02:27:48
ski: I've seen it being discussed somewhere in the context of Free encodings of monads, having quadratic runtime at worst... and using Coyoneda / Codensity it was resolved...
ertes 2017-01-31 02:28:07
mutsig: while you would use strict Text in most cases, it's never wrong and a good default to use lazy Text, if you don't know how to pick
merijn 2017-01-31 02:28:27
mutsig: lazy Text allows for a sort of "stream" processing using lazy IO, which I'm personally not a fan of (issues with resource freeing, etc.), so i would almost always use strict Text and one of the stream processing libraries (pipes or conduit) if I wanted to do streaming
ski 2017-01-31 02:28:27
(in this case by converting it to `STM a', and then `fmap'ping your functions over that. iow you're "`fmap'"ping a conversion from `TVar' to `STM', over `Coyoneda TVar', getting `Coyoneda STM', which you can then trivially lower)
systadmin 2017-01-31 02:29:26
hi
puregreen 2017-01-31 02:29:42
I want something like 'isolate' from binary, but only enforcing the upper bound (i.e. "don't consume more bytes than X"). I haven't found anything in binary that could do that, so I wrote my own by ripping out the code of 'isolate' and modifying it in an obvious way. Are there any pitfalls that I don't know about? (Because I kinda feel that if it's not in 'binary', there might've been some reason for that.)
ski 2017-01-31 02:30:07
roxxik : basically, it's the same problem as left-associating `(++)', `(((xs0 ++ xs1) ++ xs2) ++ xs3) ++ xs4' will traverse `xs0' (or rather copies of it) four times, `xs1' three times, `xs2' two times, `xs3' one time
merijn 2017-01-31 02:30:53
puregreen: Well, if you allow consumption of less than X you need to remember to "put back" the leftover input
puregreen 2017-01-31 02:31:01
yep, I have done that
ertes 2017-01-31 02:31:05
ski: Yoneda is just the precomposition version of Coyoneda, right?
ski 2017-01-31 02:31:07
roxxik : only that here, it's left-associating `(>>=)', or doing repeated `fmap' traversals after each other, or .. -- where in each case you're only interested in the "final answer", you don't want to look at the intermediate results
ertes 2017-01-31 02:31:53
like: Yoneda precomposes in negative position, Coyoneda postcomposes in positive position (so it has the function as a field)
ski 2017-01-31 02:32:06
ertes : `CoYoneda f b = exists a. (f a,a -> b)',`Yoneda f a = forall b. (a -> b) -> f b'
ski 2017-01-31 02:32:50
ertes : so, looks like you're right
roxxik 2017-01-31 02:32:52
yah, i know, but it was discussed there that codensity is more then needed and a simple yoneda is enough yielding an encoding of F f = forall r. (a -> r) -> (forall x. (x -> r) -> f x -> r) -> r, which is a bit hard to untangle if not viewed through it's CT abstration
mutsig 2017-01-31 02:33:07
ertes, merijn : thx
merijn 2017-01-31 02:33:50
puregreen: Well, the only real downside would be "it could be expensive to compute"
ertes 2017-01-31 02:33:55
roxxik: understanding church encoding can help you understand something like that from a different angle
puregreen 2017-01-31 02:34:12
merijn: what do you mean by "expensive to compute"?
ertes 2017-01-31 02:34:40
roxxik: type List a = forall r. (a -> r -> r) -> r -> r -- how is this a list type?
merijn 2017-01-31 02:35:03
puregreen: Well, grabbing a section and running a new parser on that could be expensive, depending on the size and subparser
roxxik 2017-01-31 02:35:06
:t foldr
lambdabot 2017-01-31 02:35:08
Foldable t => (a -> b -> b) -> b -> t a -> b
roxxik 2017-01-31 02:35:40
:t \l f z -> foldr f z l
lambdabot 2017-01-31 02:35:42
Foldable t => t a -> (a -> b -> b) -> b -> b
roxxik 2017-01-31 02:35:55
fromList
roxxik 2017-01-31 02:36:21
:t \cl -> cl cons [] -- toList
lambdabot 2017-01-31 02:36:22
Cons s s a a => ((a -> s -> s) -> [t1] -> t) -> t
roxxik 2017-01-31 02:36:34
:t \cl -> cl (:) [] -- toList
lambdabot 2017-01-31 02:36:37
((a -> [a] -> [a]) -> [t1] -> t) -> t
roxxik 2017-01-31 02:37:01
:t \cl -> cl (:) [] :: [a] -- toList
lambdabot 2017-01-31 02:37:03
error:
lambdabot 2017-01-31 02:37:03
• Couldn't match expected type '(a0 -> [a0] -> [a0])
lambdabot 2017-01-31 02:37:03
-> [t0] -> [a1]'
roxxik 2017-01-31 02:37:05
meh
ski 2017-01-31 02:37:07
@type GHC.Base.build
roxxik 2017-01-31 02:37:08
w/e
lambdabot 2017-01-31 02:37:09
(forall b. (a -> b -> b) -> b -> b) -> [a]
ski 2017-01-31 02:37:18
(it needs rank-2)
roxxik 2017-01-31 02:37:33
that can't be inferred?
ski 2017-01-31 02:37:45
well, technically i think it can, but GHC doesn't try
roxxik 2017-01-31 02:37:50
ah ok
merijn 2017-01-31 02:37:50
roxxik: In *theory* Rank2 is inferrable
merijn 2017-01-31 02:38:02
roxxik: But the implementation of Rank2 inference is hell, so GHC doesn't do it
merijn 2017-01-31 02:38:14
roxxik: RankN (with N>2) is proven impossible to infer
ski 2017-01-31 02:39:01
roxxik : hmm, your `F f a' looks like `Yoneda (\r -> Cont r (Coyoneda f r)) a' ..
roxxik 2017-01-31 02:39:40
you have a type level lambda there :O
ski 2017-01-31 02:39:50
well, yes
ski 2017-01-31 02:42:07
so for some reason we're making `f' into a functor (in one way) before feeding to `Cont', picking `r' both as final result type, and as "action result element type", and then turning the result of that into a functor (in the other way), before setting the "elemenr type" "viewed externally" to `a'
quchen 2017-01-31 02:42:12
:t \n c -> foldr c n -- ski, roxxik: no, it cannot be inferred, because it still typechecks when we float out the ∀, so the type is ambiguous with rank-2
lambdabot 2017-01-31 02:42:14
Foldable t => b -> (a -> b -> b) -> t a -> b
quchen 2017-01-31 02:42:22
:t build
lambdabot 2017-01-31 02:42:23
error:
lambdabot 2017-01-31 02:42:23
• Variable not in scope: build
lambdabot 2017-01-31 02:42:24
• Perhaps you meant 'buildG' (imported from Data.Graph)
quchen 2017-01-31 02:42:45
Eh, see above. Anyway, both the existential-build and the universal-build typecheck.
quchen 2017-01-31 02:42:55
(And they are the same term.)
ski 2017-01-31 02:43:51
quchen : so you're saying "In *theory* Rank2 is inferrable" is false ?
ertes 2017-01-31 02:44:25
quchen: inferring an ambiguous type ≠ being unable to infer
quchen 2017-01-31 02:45:05
Okay, »uniquely inferrable«.