code logs -> 2016 -> Tue, 26 Jul 2016< code.20160725.log - code.20160727.log >
--- Log opened Tue Jul 26 00:00:05 2016
00:10 Kindamoody is now known as Kindamoody[zZz]
01:16 himi [sjjf@Nightstar-dm0.2ni.203.150.IP] has joined #code
01:16 mode/#code [+o himi] by ChanServ
02:19 catadroid` [catadroid@Nightstar-k6cq59.dab.02.net] has joined #code
02:21 catadroid [catadroid@Nightstar-1o014u.dab.02.net] has quit [Ping timeout: 121 seconds]
02:33 Turaiel[Offline] is now known as Turaiel
03:00 macdjord|slep [macdjord@Nightstar-r9vt2h.mc.videotron.ca] has quit [Connection closed]
03:01 macdjord|slep [macdjord@Nightstar-r9vt2h.mc.videotron.ca] has joined #code
03:01 mode/#code [+o macdjord|slep] by ChanServ
03:18 macdjord|slep [macdjord@Nightstar-r9vt2h.mc.videotron.ca] has quit [Connection closed]
03:19 macdjord|slep [macdjord@Nightstar-r9vt2h.mc.videotron.ca] has joined #code
03:19 mode/#code [+o macdjord|slep] by ChanServ
03:29 macdjord|slep [macdjord@Nightstar-r9vt2h.mc.videotron.ca] has quit [Ping timeout: 121 seconds]
03:32 macdjord [macdjord@Nightstar-r9vt2h.mc.videotron.ca] has joined #code
03:32 mode/#code [+o macdjord] by ChanServ
04:12 macdjord [macdjord@Nightstar-r9vt2h.mc.videotron.ca] has quit [Connection closed]
04:13 macdjord [macdjord@Nightstar-r9vt2h.mc.videotron.ca] has joined #code
04:13 mode/#code [+o macdjord] by ChanServ
04:19 mac [macdjord@Nightstar-r9vt2h.mc.videotron.ca] has joined #code
04:19 mode/#code [+o mac] by ChanServ
04:23 macdjord [macdjord@Nightstar-r9vt2h.mc.videotron.ca] has quit [Ping timeout: 121 seconds]
05:05 Derakon is now known as Derakon[AFK]
05:08 * Alek just sat down and did the recursive isEven exercise.
05:08
<@Alek>
I.... think I did good?
05:08
<@Alek>
function isEven(number) {
05:08
<@Alek>
if (number == 0)
05:08
<@Alek>
return true;
05:08
<@Alek>
else if (number == 1)
05:08
<@Alek>
return false;
05:08
<@Alek>
else if (number < 0)
05:08
<@Alek>
return isEven(number + 2);
05:08
<@Alek>
else
05:08
<@Alek>
return isEven(number - 2);
05:08
<@Alek>
}
05:08
<@Syloq>
pastebin...
05:09
<@Alek>
sorry.
05:11
<&McMartin>
Looks like you should be able to make some easy testcases for that to make sure it works out
05:12
<&McMartin>
Don't make them too big, JS doesn't do the optimization that makes code like this safe~
05:16
<@Syloq>
I'll never understand the need/use of recursive functions. If something goes wrong it eats up so much time trying to debug. Not to mention readability is horrible.
05:18
<&McMartin>
Then you're doing it wrong, basically~
05:18
<&McMartin>
You can read the past execution up to the failure point out of the stack trace, normally
05:19 JustLurk [justbob@ServerAdministrator.Nightstar.Net] has joined #code
05:19 JustBob [justbob@Nightstar.Customer.Dissatisfaction.Administrator] has quit [NickServ (RECOVER command used by JustLurk)]
05:19 JustLurk is now known as JustBob
05:19 mode/#code [+o JustBob] by ChanServ
05:20
<@Syloq>
Depending on your language. sure.
05:20
<&McMartin>
C++, here
05:20
<&McMartin>
Cases where it gets stickier are things like DFS, where you can do it recursively but you usually wouldn't so that you can swap out search strats...
05:21
<&McMartin>
... but at that point you have an extra stack you're dicking around with that really might as well be the call stack, too
05:21
<@Syloq>
I've just found that no matter what language you're using it just becomes a burden to someone at some point.
05:23
<&McMartin>
So does iteration
05:23
<&McMartin>
That said, unless your langauge has tailcall elimination, the usual clue that you should be doing it recursively is that you find yourself re-implementing function call mechanics.
05:23
<&McMartin>
(Usually while marshalling/demarshalling/parsing/etc recursive data structures)
05:28
<@Syloq>
heh I suppose so.
05:29
<@Syloq>
I just know that I wouldn't ever do it with a scripting language like JS. Unless you're trying to prove that you can....not that you should.
05:29
<&McMartin>
Which this one is, since it's teaching recursive problems
05:29
<&McMartin>
(That said: parsing JSON without use of eval)
05:29
<&McMartin>
(You want the recursive calls for the elements of arrays and objects)
05:32
<@Syloq>
Well I suppose, but why reinvent the wheel? I get the learning aspect of "Yes you can create recursive functions and this is how..." The real world has tons of libraries and have been battle tested..much more than anything you could write alone.
05:36
<@Pi>
Syloq: As another perspective, recursion and iteration are ultimately different syntaxes for the same thing.
05:37
<@Pi>
Or alternatively, iteration is the special case of tail recursion.
05:37
<@Syloq>
Sure. I can see that.
05:38
<@celticminstrel>
Still haven't solved that SDL_ttf+OpenGL issue... I should get back to it, but I'm really not sure how to approach the problem...
05:42
<@Alek>
McM: the example boxes provide testcases.
05:42
<&McMartin>
Pi: Disagree: recursion is strictly more poewrful than iteration
05:42
<&McMartin>
Iteration + Cons is as powerful, though :D
05:44
<@Pi>
McMartin: That's what I meant with iteration being the special case of tail recursion, yeah.
05:55 * Vornicus <3 recursion
06:10 Turaiel is now known as Turaiel[Offline]
06:26 Vornicus [Vorn@ServerAdministrator.Nightstar.Net] has quit [Connection closed]
07:05 Kindamoody[zZz] is now known as Kindamoody
07:25
<@Alek>
gah. why am I getting an unexpected identifier from what seems to be a straightforward if boolean check?
07:25
< catadroid`>
Check spelling and case?
07:26
< catadroid`>
Missing and /or accidental semi colons?
07:30
<@Alek>
that didn't seem to be the case.
07:31
<@Alek>
but replacing the if with a ternary with a null-effect else worked. -_-
07:31 * Alek glares.
07:31
<@Alek>
http://eloquentjavascript.net/03_functions.html#h_3rsiDgC2do
07:31
<@Alek>
this exercise.
07:32
<@Alek>
and yeah, I know my code won't show up there. >_>
07:35
< catadroid`>
What's the full error message?
07:37
<@Alek>
Uncaught SyntaxError: Unexpected identifier (line 8)
07:37
< catadroid`>
Ah, that's not overly helpful
07:38 Kindamoody is now known as Kindamoody|afk
07:38
<@Alek>
...
07:38
<@Alek>
well damn.
07:38
<@Alek>
so apparently the sample code using if I looked at earlier did not use parens around the comparison.
07:38
<@Alek>
but it was supposed to.
07:38
<@Alek>
and that's what the problem was.
07:38 * Alek headdesks.
07:39 * catadroid` nods
07:40
<@Alek>
that solved, if works. ternary works too, but there really is no need since there isn't anything to do on false.
07:40
<@Alek>
so I just had it set the count to itself, which is really wasteful. >_>
07:40
<@Alek>
so if is the better way to go here.
07:41
<@Alek>
and that's the chapter done. off to bed with me.
07:41
< catadroid`>
Night!
07:42
<@Alek>
I swear, I'm gonna have to put huge posters around me, for each language, showing example usage of every single basic command.
07:42
<@Alek>
because I can NOT trust my memory.
07:44
<@Alek>
there also needs to be some kind of guide on when to use semicolons and when not to. <_<
07:45
< catadroid`>
In javascript it's worse because it automatically inserts them at the end of every line regardless
07:53 catadroid` [catadroid@Nightstar-k6cq59.dab.02.net] has quit [[NS] Quit: Bye]
07:54
<&McMartin>
Not *quite* regardless, but close enough as to make one's life hell
07:54
<&McMartin>
Still better than Go, where it *is* regardless, and thus this is legal but does not do what you want:
07:54
<&McMartin>
if (a < b)
07:54
<&McMartin>
{
07:54
<&McMartin>
return true;
07:54
<&McMartin>
}
07:54
<&McMartin>
Which checks a<b and if it is, does nothing, and then returns true no matter what
07:58 himi [sjjf@Nightstar-dm0.2ni.203.150.IP] has quit [Ping timeout: 121 seconds]
08:18 celticminstrel is now known as celmin|sleep
08:52 celmin|sleep [celticminst@Nightstar-nhhr58.dsl.bell.ca] has quit [[NS] Quit: And lo! The computer falls into a deep sleep, to awake again some other day!]
09:40 catadroid [catadroid@Nightstar-977skp.dab.02.net] has joined #code
09:41
< catadroid>
WHY ISN'T CLOJURE EVERY LANGUAGE
09:41
< catadroid>
ahem
09:41
< catadroid>
More accurately - why isn't every language clojure
09:41
< catadroid>
Transducers are making me legitimately hawt and bothered
10:07
<@simon>
catadroid, all languages have transducers. all languages that aren't explicit about having them are crap at it, though. :P
10:08 * simon likes to think in terms of "C#'s IO monad is really poor", even though it's probably wrong to view the language with models of computation in mind that weren't intended by the authors.
10:13
<@TheWatcher>
Meanwhile I'm trying to bugfix jenkins plugins, so java and maven and kill me now.
10:13
<@simon>
catadroid, I'm probably in the ML > Lisp camp. I don't know if Greenspun's tenth rule extends to ML/Haskell, too...
10:17 * TheWatcher thumbtwiddles as `mvn install` downloads half the fucking internet as usual
10:23
< catadroid>
The IO monad is something I need to form a concise definition of before I would talk more about it
10:24
< catadroid>
Everyone is so crap at explaining what it is
10:24
< catadroid>
And not all languages have abstract transducers specified in a useful way separate from their container types
10:24
< catadroid>
In fact... virtually none to
10:24
< catadroid>
Do*
10:25
< catadroid>
Clojure just seems usable in ways that Haskell just isn't to me right now
10:28
< catadroid>
I strongly suspect that the reason people are bad at explaining monads is because they start by being too mathematical about them
10:58
<@Pi>
catadroid: I would first suggest dropping "monad" from the name :)
10:58
<@Pi>
Just IO action is fine.
11:26 Emmy [Emmy@Nightstar-9p7hb1.direct-adsl.nl] has joined #code
11:26 mode/#code [+o Emmy] by ChanServ
11:28
< catadroid>
Well, the thing is that monads are a useful concept for scoping
11:28
< catadroid>
And general concept of context, in particular explicit context
11:28
< catadroid>
Implicit context*
11:28
< catadroid>
Abstracted context.
11:28
<@Pi>
catadroid: The thing is, that has less to do with monads, and more to do with functors.
11:29
<@Pi>
I suspect 90% of what people talk about when they talk about monads are actually just about functors and applicative functors.
11:29
<@Pi>
That's why I always emphasis those first.
11:29
< catadroid>
Whilst that may be true, monad is the word you always hear
11:29
<@Pi>
Learning the Functor abstraction is 50% of the battle.
11:29
<@Pi>
Learning Applicative is 30% further.
11:29
<@Pi>
And Monad is maybe the last 20 or 10%
11:30
<@Pi>
And it's really pretty obvious and boring by comparison, once you grok Functor and Applicative.
11:30
< catadroid>
The biggest problem with nearly all descriptions of monads I've read is that they start abstract and by the time they get to concretely useful code I want to end my existence I'm so bored
11:30
<@Pi>
catadroid: Yeah, monad tutorials are the worst.
11:30
<@Pi>
(Needs more Functor tutorials!)
11:31
< catadroid>
It's a lot like learning how to use statistics
11:33
<@Pi>
By the way, does anyone want a mini-tutorial or discussion of Haskell's IO actions now?
11:33
<@Pi>
I could always talk about that. :)
11:41 himi [sjjf@Nightstar-v37cpe.internode.on.net] has joined #code
11:41 mode/#code [+o himi] by ChanServ
11:43
< catadroid>
I would be up for that if I didn't have work to do
12:30
< catadroid>
I am honestly experiencing the 'everything is just a less powerful, less expressive implementation of LISP' right now
12:31
<@simon>
catadroid, from the practical experience I've gathered, monads are mostly about composing asymmetric functions, but still make them follow a standard design. e.g. instead of (A -> B) o (B -> C), you might have (A -> (B, C)) o (B, (D, E)) where handling C is abstracted into the composition operator.
12:32
<@simon>
whoops, (A -> (B, C)) o (B -> (D, E))
12:32
<@simon>
neat ways to compose functions that do other things than deliver output to the next function's input, and syntax sugar to make those operations implicit.
12:33
<@simon>
as Pi suggests, not calling it "a monad" is probably the first thing to boost understanding. that'd be like calling uint32_t a commutative monoid.
12:34
<@Pi>
Or talking about lists as "the list summable"
12:35
<@simon>
catadroid, so the whole monadic approach in haskell seems very similar to e.g. transducers. it's all about adding abstraction to function composition.
12:35
<@Pi>
Sure, you can sum lists, but that's not all that lists are about.
12:35
< catadroid>
Yeah, transducers seem like a pure abstract concept I've not seen before
12:35
<@Pi>
Same with IO actions: Sure, you can use join on them (what Monad provides), but more often than not you don't, and that's all they're about.
12:36
< catadroid>
I thought the IO monad was largely about forcing most functions to be lazy and pure by default
12:36
<@Pi>
It has nothing to do with lasiness or purity.
12:36
<@Pi>
laziness, even
12:37
<@simon>
catadroid, that's a parallel goal.
12:37
<@Pi>
If you're familiar with Deferreds or Promises in other languages, IO actions are probably most intuitively similar to them.
12:38
<@Pi>
And you should then probably know that those don't have anything to do with laziness or purity either.
12:38
<@simon>
catadroid, you can have eager IO actions, and you could write all your Haskell functions with 'IO ...' as the return type, making them not very pure. but you'd probably not want to. :P
12:38
<@Pi>
You can implement Haskell-style IO actions in any language, with or without laziness or purity.
12:38 * gnolam flails at abstraction.
12:38
<@Pi>
It's just an API and set of semantics.
12:38
<@Pi>
For representing and working with first-class effects.
12:39
<@Pi>
(as opposed to side effects)
12:39
<@gnolam>
Every bit of hardware so far could be easily abstracted through the same interface, but not this one, nosiree.
12:39 * gnolam sighs.
12:39
<@gnolam>
Back to the old drawing board...
12:39
<@simon>
first-class effects being effects that are represented as values, right?
12:39
<@Pi>
simon: Right.
12:39
<@Pi>
So for example, in Haskell, you can have a list of print actions.
12:39
<@Pi>
Like [print "foo", print "bar"]
12:40
<@Pi>
Those represent effects to be performed, but they don't get performed as _side_ effects.
12:40
<@Pi>
They only get performed when actually executed, as a separate step to program evaluation.
12:41
< catadroid>
I don't understand the distinction
12:41
<@Pi>
For example, your top-level Haskell program can be:
12:41
<@Pi>
main = [print "foo", print "bar"] !! 1
12:41
<@Pi>
That will only print bar
12:41
<@simon>
catadroid, I haven't done any commercial Haskell hacking, so I also don't know if it can be that language for me. but I'd be willing to try.
12:41
<@gnolam>
And while I'm in here waiting for my tea to brew: help generation systems.
12:41
<@gnolam>
I want to be able to generate in-program help as well as a printable manual. Preferably with multiple languages supported out-of-the-box.
12:41
<@Pi>
Regardless of whether print "foo" gets evaluated or not.
12:41
<@gnolam>
Any recommendations?
12:42
<@Pi>
catadroid: Side effects happen as a side effect to evaluation.
12:42
<@Pi>
So with side effects, the evaluation of (print "foo") might result in nothing, but actually goes and prints the value as a side effect.
12:43
< catadroid>
So it's a value that leaks out by means other than effectively being the value of the expression
12:43
< catadroid>
Like exceptions?
12:43
<@Pi>
With first-class effects, the evaluation of (print "foo") gives you a first-class effect as return value, which can be passed around, duplicated, recomposed, etc.
12:43
< catadroid>
That makes some sense
12:43
< catadroid>
So it effectively returns a value that has an action when evaluated?
12:43
<@Pi>
So for example, with first class effects, you can do things like: sequence (replicate 5 (print "foo"))
12:44
<@Pi>
The replicate 5 just takes an arbitrary value and turns it into a list of 5 copies.
12:44
<@Pi>
And sequence combines all the effects in a list, in this case.
12:44
< catadroid>
How do you make that actively print?
12:45
<@Pi>
In Haskell, your whole program ends up being a combined effect value that you assign to "main"
12:45
<@Pi>
And that effect gets executed when you run the program.
12:45
<@Pi>
You can also execute effects by evaluating them at the ghci prompt.
12:45
< catadroid>
So execution is an external concept?
12:45
<@Pi>
Right.
12:45
<@Pi>
It's entirely separate to evaluation.
12:45
<@simon>
it's my impression that other effects get executed when the real world tugs at it.
12:46
< catadroid>
So it's the Print in REPL
12:46
<@Pi>
So that's the key definition: if your effects are tied to evaluation, then they're side effects (of evaluation) by definition.
12:46
<@Pi>
And side effects break referential transparency.
12:46
< catadroid>
And Eval is literally Eval not EvalAndSideEffects
12:46
<@Pi>
Right.
12:47
<@Pi>
So, with that earlier example again: sequence (replicate 5 (print "foo"))
12:47
<@Pi>
if that print was a side effect, then that program wouldn't work at all.
12:47
< catadroid>
REXL
12:47
<@Pi>
It wouldn't print five copies of "foo", it would just print "foo" and then evaluate to a list of 5 nothings.
12:47
< catadroid>
Which you see all the time if you look at the return values of things like def or println
12:48
<@Pi>
So in a language with side effects, you can't necessarily refactor [x, x, x, x, x] into "replicate 5 x"
12:48
< catadroid>
They affect the environment but that's not directly reflected in their value
12:48
<@Pi>
Because the expression x may have side effects.
12:48
< catadroid>
Dammit now I like Haskell a lot more
12:48
<@Pi>
But in Haskell, you can, even when x is an IO action like (print "foo")
12:49
<@Pi>
It's a very powerful thing. :)
12:49
<@Pi>
It means you can factor and reason about your code equationally, just like high school algebra, and not get tripped by side effects.
12:49
< catadroid>
And the IO monad is a marker that they are actions and eval to an individual action instance not a value
12:50
<@Pi>
It also means that Haskell doesn't need the same numerous and fancy control structures that imperative languages have to control evaluation order.
12:50
<@Pi>
Instead of special control structures, you just have normal data manipulation functions.
12:50
<@Pi>
Because effects are just another kind of data.
12:50
<@Pi>
And custom user-defined control structures are just plain libraries.
12:50
< catadroid>
Is my statement about IO correct above?
12:51
<@Pi>
catadroid: Well, I would just say "IO actions are normal values that describe an effect to be performed."
12:51
< catadroid>
Sure, but they can't be replaced by the same instance of a value when optimised, right?
12:51
<@simon>
Pi, thanks for that explanation of first-class effects. :)
12:51
<@Pi>
catadroid: How do you mean?
12:51
< catadroid>
They essentially evaluate to themselves?
12:51
<@Pi>
Right.
12:51
<@Pi>
They're really just plain values.
12:52
< catadroid>
So actions are a first class concept in the same manner that numeric literals are
12:52
<@Pi>
If you want to, you can imagine a Haskell program's compilation as evaluating the "main" value as far as possible (which is an IO action), and then just translating that big composite IO action into assembly
12:52
<@Pi>
or whatever.
12:52
<@Pi>
catadroid: Exactly.
12:52
< catadroid>
In that they're irreducible
12:52
<@Pi>
They're just plain data
12:52
<@Pi>
Nothing special.
12:53
< catadroid>
That's a fabulous insight
12:53
<@Pi>
Plain data, with an API to compose and combine them.
12:53
<@Pi>
And work with their results.
12:53
< catadroid>
I suppose numeric literals are also IO actions
12:53
<@Pi>
Not exactly.
12:54
< catadroid>
In that they're loaded into a register or whatnot
12:54
<@Pi>
Numeric literals and IO actions are just two different kinds of data values.
12:54
< catadroid>
I'm being loose with terms
12:54
<@Pi>
You can have a list of both :)
12:54
<@Pi>
For example
12:55
<@Pi>
In most cases, working with functors (like IO actions) in Haskell is just a slight variation of working with pure values.
12:55
< catadroid>
Yeah, but in the final compiled assembly they are combined into instructions
12:56
<@Pi>
So for example:
12:56
<@Pi>
ghci> length $ "hello"
12:56
<@Pi>
5
12:57
<@Pi>
If you want "hello" to be a line of user input instead, you apply the function with <$> instead of $
12:57
<@Pi>
ghci> length <$> getLine
12:57
<@Pi>
test
12:57
<@Pi>
4
12:57
<@Pi>
(There, the "test" is user input"
12:57
<@Azash>
http://news.softpedia.com/news/nist-prepares-to-ban-sms-based-two-factor-authent ication-506617.shtml
12:58
<@Pi>
But "length <$> getLine" is itself just a modified IO action: <$> takes an existing IO action and applies a function to its result.
12:58
<@Pi>
In other words:
12:58
<@Pi>
getLine :: IO String
12:58
<@Pi>
length <$> getLine :: IO Int
12:59
<@Pi>
So getLine is a value of type (IO String), which means an IO action yielding a String, and (length <$> getLine) builds a new IO action of type (IO Int), which is an IO action yielding an Int.
12:59
<@Pi>
None of this involves monads: it's all just Functor and IO actions.
13:00
<@Pi>
The next thing you can do with IO actions is to combine more than one IO action together.
13:01
<@Pi>
For example, let's say you want to write a helper that prompts the user for input, with a custom prompt string:
13:01
<@Pi>
prompt p = putStr p *> getLine
13:01
<@simon>
Azash, interesting. I wonder if there'll be a market for pure identity/authentication services. currently, my Gmail is probably more important to me as an authentication service than a communication device.
13:01
<@Pi>
prompt :: String -> IO String
13:01
<@Pi>
ghci> prompt "Name? "
13:01
<@Pi>
Name? Pi
13:01
<@Pi>
"Pi"
13:02
<@Pi>
So (prompt "Foo? ") constructs a new IO action that will print out "Foo? " and then read a line, and return that.
13:02
<@Pi>
And it does that by sequencing two IO actions, putStr "Foo? " and getLine
13:02
< catadroid>
Why isn't <$> the same as $?
13:02
<@Pi>
(foo *> bar) is the sequencing primitive.
13:03
<@Pi>
And that's part of Applicative, for applicative functors.
13:03
<@Pi>
(still no monads anywhere, by the way. :)
13:03
<@simon>
($) :: (a -> b) -> a -> b while (<$>) :: Functor f => (a -> b) -> f a -> f b
13:03
<@Pi>
catadroid: It's in order to distinguish between the level of application you want to do.
13:04
<@Pi>
$ does pure / direct application, while <$> does functorial application.
13:04
<@Pi>
catadroid: For example, lists are functors. If you apply "length" directly to a list with $, you get the length of the list itself.
13:04
<@Pi>
If you apply length with <$>, then you operate on the elements instead, and get a new list of their individual lengths
13:05
<@Pi>
Same for IO actions: if you apply functions directly with $, then you operate on the IO actions itself as a value.
13:05
<@Pi>
For example, (replicate 5 getLine) takes the action itself as a value, and duplicates it 5 times into a list.
13:05
<@Pi>
That's the same as (replicate 5 $ getLine)
13:06
<@Pi>
But if you use <$>, then you operate on the *result* of the IO action, rather than the IO action itself.
13:06
<@Pi>
So (replicate 5 <$> getLine) would mean to read a *single* line, and then duplicate the value that was read 5 times.
13:06
<@Pi>
As opposed to giving you a list of 5 getLine actions.
13:07
<@Pi>
Does that make sense?
13:07
<@Pi>
Basically, <$> means you want apply some function inside a functor, rather than outside it.
13:08
<@Pi>
ghci> length $ ["abra","cadabra"]
13:08
<@Pi>
2
13:08
<@Pi>
ghci> length <$> ["abra","cadabra"]
13:08
<@Pi>
[4,7]
13:08
<@Pi>
(The latter <$> is like map)
13:31
< catadroid>
Aha
13:31
< catadroid>
I see it but I don't intuit it yet
13:32
<@Pi>
If you look at the signature, you can see the functor as representing some kind of computational structure or context, and <$> applies a function inside of it: (<$>) :: Functor f => (a -> b) -> f a -> f b
13:33
<@Pi>
So the f can be IO, or Maybe, or [], or whaever
13:33
<@Pi>
Any Functor instance
13:34
<@Pi>
And all functors basically have an idea of a "typed slot" that you operate on.
13:34
<@Pi>
For IO actions, it's the result value
13:34
<@Pi>
For Maybe, it's the optional value, if it's present.
13:34
<@Pi>
For [], it's the list elements.
13:34
<@Pi>
And so on.
13:42 * TheWatcher is, randomly, reminded that he hates java
13:52 Turaiel[Offline] is now known as Turaiel
14:03
< catadroid>
Pi: that all makes a lot of sense. So could <$> be described as a kind of destructuring application?
14:03
<@Pi>
Perhaps. A more accurate description might be "structure-preserving application"
14:03
<@Pi>
"structure-preserving" is actually central to the entire idea of functors.
14:03
< catadroid>
It does remind me of the way transducers are applied to collections
14:04
<@Pi>
All functors represent some distinction between a structure, and a slot.
14:04
<@Pi>
For IO actions, the structure is action's effect, and the slot is the action's result.
14:04
<@Pi>
So when you use <$> with IO actions, "structure-preserving" means "effect-preserving"
14:05
<@Pi>
In other words, when you operate on an action's result with <$>, you're guaranteed that the action's effect won't be altered.
14:05
<@Pi>
The same holds for every other functor.
14:05
<@Pi>
For example, for lists, the structure is the list's size and order (and the slots are the elements)
14:06
<@Pi>
And "structure-preserving" means "size and order preserving"
14:06
<@Pi>
So <$> (IOW map) with a list guarantees that that the list shape doesn't change: the elements stay in the same order, and none get introduced or eliminated.
14:07
<@Pi>
Every other functor has its own definition of structure, and <$> will always preserve it.
14:07
<@Pi>
(while operating inside it)
14:13
< catadroid>
Hm
14:13
< catadroid>
So <$> is essentially map?
14:13
<@Pi>
For lists, it's equivalent to map, yes.
14:14
<@Pi>
The older name for <$> is also `fmap`, for "functor map"
14:15 macdjord|slep [macdjord@Nightstar-r9vt2h.mc.videotron.ca] has joined #code
14:15 mode/#code [+o macdjord|slep] by ChanServ
14:16
<&ToxicFrog>
"The older name for <$> is also `fmap`, for "functor map""
14:16
<&ToxicFrog>
This retroactively makes a bunch of stuff make more sense.
14:17 mac [macdjord@Nightstar-r9vt2h.mc.videotron.ca] has quit [Ping timeout: 121 seconds]
14:18
<@Pi>
I don't like focusing on the map intuition too much, though, because it only really makes sense for data-structure-like functors, and functors are not limited to that.
14:19
<@Pi>
It leads to people building up bad intuitions like "functors are a generic interface to containers"
14:19
<@Pi>
Which doesn't make sense for e.g. IO or State actions
14:20
<@Pi>
It's much more precise and useful to just think of <$> as modified kind of function application, for when you want to apply functions to functorial values instead of plain / pure values.
14:21
<@Pi>
(another older name for <$> is `ap`, for "application")
14:25
<&ToxicFrog>
Pi: I mean, things I've read previously that used <$> and fmap interchangeably without ever really explaining what they were for or that they were in fact the same thing
14:25
<@Pi>
Oh, yeah, they're literally the same thing.
14:26
<@Pi>
Prefix versus infix syntax.
14:26
<@Pi>
fmap f x == f <$> x
14:26
<@Pi>
(<$>) f x == f `fmap` x
14:27
<@Pi>
($) = fmap and vice versa
15:03
<@simon>
Pi, I guess it's like saying it works for any function and then focus specifically on algebraic value constructors.
15:04
<@Pi>
Yeah.
15:06 Vornicus [Vorn@ServerAdministrator.Nightstar.Net] has joined #code
15:06 mode/#code [+qo Vornicus Vornicus] by ChanServ
15:14
< catadroid>
So a functor is a context that allows wrap and unwrap to apply a function to the thing it wraps
15:14
< catadroid>
Via fmap
15:14
<@Pi>
Some are.
15:14
<@Pi>
"wrapping" is another bad intuition, though.
15:15
<@Pi>
Data structures wrap, but other functors don't
15:15
< catadroid>
What's an example of one that doesn't?
15:15
<@Pi>
For example, there's no way to "unwrap" an IO action.
15:15
<@Pi>
It's an action to be performed.
15:15
<@Pi>
You execute IO actions, you don't unwrap them.
15:16
< catadroid>
Sure, but you're removing the IO context, performing the transform via your function and then readding it, conceptually, right?
15:16
<@Pi>
Not really.
15:16
<@Pi>
You're just operating on a future value, before it arrives.
15:16
<@Pi>
It's like adding a callback, if you want better intuition.
15:16
<@Pi>
You wouldn't call adding a callback "unwrapping", right?
15:16
< catadroid>
So you're effectively adding a transducer to the action?
15:17
< catadroid>
That doesn't feel right
15:17
< catadroid>
(my sentence)
15:18
<@Pi>
I'm not that familiar with transducers in detail
15:18
<@Pi>
All that <$> does in the case of IO actions is to arrange for a function to be applied to the action's result, though.
15:18
< catadroid>
The thing is, that IO a -> IO a applying an f that's a -> a can be used with fmap, I think?
15:19
<@Pi>
Right.
15:19 catadroid` [catadroid@Nightstar-breon6.dab.02.net] has joined #code
15:19
<@Pi>
So that arranges for f to b applied to th former IO action's result, yielding a new modified IO action.
15:19
< catadroid`>
Grr interwebs
15:20
< catadroid`>
So you've taken an IO action, and made a new IO action that's the composite of your old action's result and an operation that's then placed back into the IO context
15:21
< catadroid`>
So you're basically wrapping and wrapping and wrapping and your value travels outwards the entire time
15:22
<@Pi>
Well, except without any wrapping and unwrapping :)
15:22
<@simon>
"unwrapping IO" is kind of like "letting time pass".
15:22
< catadroid`>
Well, there is no unwrapping
15:22
<@simon>
the metaphor is really off.
15:22
< catadroid`>
^ that
15:22
<@Pi>
You can think of [] and Maybe and other data structures as wrapping and unwrapping if you want to, but it doesn't really make any sense in the context of IO actions.
15:22
< catadroid`>
Yeah, but my mind is very very stuck in LISP concepts right now
15:22 catadroid [catadroid@Nightstar-977skp.dab.02.net] has quit [Ping timeout: 121 seconds]
15:23
<@Pi>
Even then, I prefer thinking of it more as just operating on slots inside some structer.
15:23
<@Pi>
structure, even
15:23
<@Pi>
Not "unwrapping" and "wrapping"
15:23
<@Pi>
That makes it sound like the structure can change.
15:23
< catadroid`>
The problem is I have a specific diagram from Hickey's transducer talk in my head
15:23
< catadroid`>
When I say wrapping
15:23
<@Pi>
When in fact the entire point of Functor is guaranteeing that the structure *doesn't* change.
15:24
<@Pi>
So it's more like saying okay, you have shelf, but you're only going to modify the books, not change the shape of the shelf.
15:24
< catadroid`>
Spelunking ?
15:24
<@Pi>
It doesn't make sense to say you're going to "unwrap" the books from the shelf and then "rewrap" back in the same shelf.
15:24
<@Pi>
It really misses the focus and point of what's actually happening.
15:29
<@Pi>
The only intuition that really matters is that you have some structure, and you're going to operate on its slots without changing the surrounding structure.
15:29
<@Pi>
And also that "structure" can be arbitrary: it includes computational structures such as first-class actions and effects, not just data structures.
15:30
<@Pi>
The point is that you don't need to know anything about the structure, just that it gets preserved.
15:30
<@Pi>
And the structure gets to decide what that function application means for it.
15:30
<@Pi>
Every Functor has its own meaning for it.
15:32
<@Pi>
Another example of a functor is Either, which represents either an error value or a successful result.
15:32
<@Pi>
For Either, the slot you're operating on is just the successful result.
15:32
<@Pi>
If an Either value is an error, <$> just does nothing.
15:32
<@Pi>
And preserves the error.
15:33
<@Pi>
(that's the "structure" that gets preserved in this case)
15:33
<@Pi>
You _could_ think of this as some dance of unwrapping and rewrapping, but that just really obscures and makes things more complicated IMHO.
15:34 * Vornicus reads
15:34
< catadroid`>
So what's the structure of an IO action?
15:34
<~Vornicus>
NOLLIJ
15:35
<@Pi>
It's much simpler to say that the Either functor is like normal evaluation, except that in addition to successful values you also have errors that bypass normal evaluation and propagate.
15:35
<@Pi>
catadroid`: The structure of IO actions are the action's effects
15:35
<@Pi>
That's what gets preserved.
15:36
< catadroid`>
The unwrapping and rewrapping is just that the structure disappears and reappears in the code
15:36
< catadroid`>
That's what I'm thinking about
15:36
< catadroid`>
The structure being an abstract concept separate from the values it holds
15:36
<@Pi>
So whenever you operate on an IO action with structure preserving operators like <$>, you're guaranteed that the effects are preserved exactly: no surprise effects will be introduced or eliminated from it.
15:37
<@Pi>
So if you start with a getLine, and repeatedly extend it with <$>, then you're guaranteed that the derived IO actions will still just get one (and exactly one) line.
15:37
<@Pi>
No other effects, unless you explicitly combine them in with other combinators.
15:37 * catadroid` nods
15:37
<@Pi>
For example, the (x *> y) sequencing operator.
15:38
< catadroid`>
So the fact you are initially in the IO action context is implicitly kept along the sequence of calls?
15:38
<@Pi>
It only returns the result of the right side (y), but guarantees that the structure of both sides gets preserved.
15:38
<@Pi>
For IO, it means that the effects of both sides will happen, even though only the result of the right side is used.
15:38 ToxicFrog [ToxicFrog@ServerAdministrator.Nightstar.Net] has quit [Ping timeout: 121 seconds]
15:38
< catadroid`>
Is *> a new thing?
15:38
<@Pi>
I introduced it earlier.
15:39
< catadroid`>
Ah, so not a general Haskell thing?
15:39
<@Pi>
Oh, not, it's a Haskell thing.
15:39
<@Pi>
It's part of Applicative, for applicative functors.
15:39
<@Pi>
Example usage prompt p = putStr p *> getLine
15:39
<@Pi>
That's how you combine two IO actions into a new compound action.
15:40
<@Pi>
So now (prompt p) constructs a new IO action that will print the given prompt and then read a line, returning it.
15:43
< catadroid`>
Why not use do?
15:44
< catadroid`>
(I mean I realise that's more succinct)
15:44
< catadroid`>
(but could you use do there trivially?)
15:45
< catadroid`>
The idea of side effects being first class primitives has already mutated my thinking somewhat
15:46
<@Pi>
do syntax is just syntax sugar for *>, yeah
15:46
<@Pi>
"do x; y" == x *> y
15:48 * catadroid` nods
15:48
< catadroid`>
Does Haskell have an equivalent of LISP macros?
15:49
<@Pi>
If you've seen (>>), that's an older synonym for *> by the way.
15:49
<@Pi>
(From before the AMP proposal)
15:49
<@Pi>
catadroid`: Yeah; there are basically two kinds.
15:53
< catadroid`>
Ah, yes I recognise that symbol
15:53
< catadroid`>
I suppose that if your IO is never actually executed that removes a lot of the need for macros instead of functions
15:56
< catadroid`>
This whole idea of evaluation resulting in a list of irreducible actions makes Haskell seem actually usable
15:56
< catadroid`>
Rather than just some arbitrary ivory tower toy thing
15:58 Turaiel is now known as Turaiel[Offline]
16:06
<@Pi>
(Back, sorry! Got pulled away)
16:07
<@Pi>
catadroid`: Yeah, I was going to say, the two kinds of Lisp macros are basically new control flow primitives (for altering evaluation order), and new convenience syntax (for DSL, etc.)
16:07
<@Pi>
In Haskell, the former are primarily just plain functions and libraries, and nothing special.
16:07
<@Pi>
In other words, you don't need a macro to implement your own if: myIf cond t f = case cond of True -> t; False -> f
16:08 * catadroid` nods
16:08
<@Pi>
For the latter, you have Template Haskell, which does arbitrary compile-time syntax transformations
16:08
< catadroid`>
I wonder if smalltalk also has this characteristic
16:08
<@Pi>
In Haskell, that's usually for things like boilerplate reduction, like generating repetitive record types from shorter descriptions, etc.
16:09 * catadroid` nods
16:09
< catadroid`>
My favourite thing about lisp macros currently is that they let me create stacks of abstractions to turn virtually any problem into a declarative syntax
16:09
<@Pi>
Or embedding novel DSLs, like having raw SQL strings that compile to some Haskell primitives instead.
16:10
< catadroid`>
But I'm also aware that could just as easily be done by a function
16:10
< catadroid`>
Now I think about it
16:10
<@Pi>
Turning virtually any problem into a declarative syntax is also Haskell's raison d'etre :)
16:10
< catadroid`>
Essentially a macro is 'here's code with no eval'
16:10
< catadroid`>
Which i suppose us exactly what IO actions get you
16:11
< catadroid`>
Is*
16:11
< catadroid`>
...I may never forgive you for persuading me to program in Haskell
16:11 catadroid` is now known as catadroid
16:13
<@Pi>
catadroid: Not even IO actions, really; just non-strict evaluation.
16:14
<@Pi>
You could look at it as saying that all Haskell functions are like macros, with evaluation only on demand :)
16:14
<@Pi>
which depends on the referential transparency that's central to Haskell.
16:15
<@Pi>
In that view, all that IO actions do is make effects referentially transparent.
16:15
<@Pi>
Same for ST, STM, and many other kinds of advanced effect libraries
16:20
< catadroid>
The idea of what I've decided to call REXL sounds very enticing
16:21
< catadroid>
...dammit, now I don't even slightly care about C++
16:21
< catadroid>
Oh well
16:22 celticminstrel [celticminst@Nightstar-nhhr58.dsl.bell.ca] has joined #code
16:23 mode/#code [+o celticminstrel] by ChanServ
16:35 gizmore [kvirc@Nightstar-i5et5s.dip0.t-ipconnect.de] has joined #code
16:51 macdjord|slep [macdjord@Nightstar-r9vt2h.mc.videotron.ca] has quit [Ping timeout: 121 seconds]
16:53 macdjord [macdjord@Nightstar-r9vt2h.mc.videotron.ca] has joined #code
16:53 mode/#code [+o macdjord] by ChanServ
16:56
< catadroid>
Pi: thank you for that explanation
17:12 * catadroid considers going home
17:25
<@Pi>
catadroid: Cool :)
17:34 ToxicFrog [ToxicFrog@ServerAdministrator.Nightstar.Net] has joined #code
17:34 mode/#code [+ao ToxicFrog ToxicFrog] by ChanServ
17:36
< catadroid>
The STL's abstractions feel like they're old now :(
17:54 Vornicus [Vorn@ServerAdministrator.Nightstar.Net] has quit [Ping timeout: 121 seconds]
17:55
<&McMartin>
Yikes, backscroll
17:55
<&McMartin>
And backscroll it looks like I should read
17:56
<@abudhabi>
Is there, like, a Colonization remake that is like OpenXcom?
17:56
<@abudhabi>
NOT like Freecol?
17:57
<@abudhabi>
I don't like what they did with Freecol.
17:57
<@abudhabi>
I'd like an experience similar to OpenXcom, which basically extended the original and made it runnable on modern machines without DOSBox, but didn't do it in Java and change the interface.
18:28 catalyst [catalyst@Nightstar-bt5k4h.81.in-addr.arpa] has joined #code
18:41 Turaiel[Offline] is now known as Turaiel
18:47 catalyst [catalyst@Nightstar-bt5k4h.81.in-addr.arpa] has quit [[NS] Quit: Leaving]
18:48 Derakon[AFK] [chriswei@Nightstar-5mvs4e.ca.comcast.net] has quit [Operation timed out]
18:52 catadroid [catadroid@Nightstar-breon6.dab.02.net] has quit [The TLS connection was non-properly terminated.]
19:08 macdjord [macdjord@Nightstar-r9vt2h.mc.videotron.ca] has quit [Operation timed out]
19:09 macdjord [macdjord@Nightstar-r9vt2h.mc.videotron.ca] has joined #code
19:09 mode/#code [+o macdjord] by ChanServ
19:10
<@gnolam>
Ok, got DocBook, AsciiDoc and Markdown recommended to me elsewhere.
19:10
<@gnolam>
DocBook feels like I might as well just hand-code HTML, so I guess I'll check out the latter two.
19:26 mac [macdjord@Nightstar-r9vt2h.mc.videotron.ca] has joined #code
19:26 mode/#code [+o mac] by ChanServ
19:28 macdjord [macdjord@Nightstar-r9vt2h.mc.videotron.ca] has quit [Ping timeout: 121 seconds]
19:34
<&ToxicFrog>
astfglr. Every time I write code involving map my brain switches from python to clojure with tragic results.
19:35
<&McMartin>
My python uses of map are invariably phrased as comprehensions
19:42
<&ToxicFrog>
I basically ended up writing: print who,(map str (experiments who))
19:42
<&ToxicFrog>
And then having to revise that to: print who,map(str, experiments[who])
19:42
<&ToxicFrog>
Wait, no, there was a join in there somewhere too
19:42
<&ToxicFrog>
At least I didn't end up using ->>
19:51 Derakon [chriswei@Nightstar-5mvs4e.ca.comcast.net] has joined #code
19:51 mode/#code [+ao Derakon Derakon] by ChanServ
20:19 Derakon [chriswei@Nightstar-5mvs4e.ca.comcast.net] has quit [Operation timed out]
20:45 Derakon [chriswei@Nightstar-5mvs4e.ca.comcast.net] has joined #code
20:45 mode/#code [+ao Derakon Derakon] by ChanServ
20:54 Derakon_ [chriswei@Nightstar-5mvs4e.ca.comcast.net] has joined #code
20:54 Derakon [chriswei@Nightstar-5mvs4e.ca.comcast.net] has quit [Operation timed out]
21:08
<@Alek>
....
21:08
<@Alek>
.property vs [property].... this has great potential as well.
21:12
<@abudhabi>
Welcome to die!
21:12
<@Alek>
AND this is also how arrays work. *rubs hands in expectation*
21:12
<&McMartin>
This is actually one of the genuinely awesome bits of JS, right up until the point where it becomes terrible again
21:12
<&McMartin>
(Python is like this with dicts, objects, and modules, but arrays are a bit separate)
21:16 Turaiel is now known as Turaiel[Offline]
21:23
<@Alek>
I'm thinking of the fact that [property] allows the same function, depending on arguments, to call different properties. and also allows user input to define those properties.
21:24
<@Alek>
because of the fact that .x calls x property directly, while [x] evaluates before calling.
21:25
<&McMartin>
Yep
21:25
<&McMartin>
.x is ["x"], not [x]
21:25
<@Alek>
yup.
21:25
<&McMartin>
That's a valuable but highly dangerous technique.
21:25 * Alek nods.
21:25
<&McMartin>
In Python, you can do those to objects with the functions getattr(), hasattr(), and setattr()
21:25
<@Alek>
you may wish to standardize with .toUpperCase or .toLowerCase as well.
21:26 * Alek didn't get that far in Python.... it was past the halfway point of the book. <_<
21:26
<&McMartin>
The old joke is that incoking hasattr() three times in your code causes the King in Yellow to descend and devour your code's sanity.
21:26
<&McMartin>
*invoking
21:26 * Alek giggles.
21:26
<@Alek>
while I'm merely on chapter 4 with JS. :P
21:27
<&McMartin>
The issue with JS is that stuff that you'd be surprised to find there can kind of "leak" into your objects
21:27
<@Alek>
I could guess.
21:27
<&McMartin>
But it does sound like this particular course is covering the interesting bits of JS that can pop up elsewhere
21:28
<@Alek>
Eloquent Javascript.net
21:28
<@Alek>
book in paper and e-form. sandboxed code inline on the page. XD
21:29
<@Alek>
I like it so far.
21:29
<&McMartin>
Based on the questions you're asking, I like it too~
21:30
<@Alek>
.... when you take a specific string value, that value will always remain the same. The text inside it cannot be changed. If you have reference to a string that contains "cat", it is not possible for other code to change a character in that string to make it spell "rat".
21:31
<@Alek>
I can't help but think that there's just one .charAt(N) .push needed to let it do that...
21:33
<@Alek>
I could probably cobble together functions that convert a string to an array, search for and replace the character you want, and convert the array back to a string.
21:33
<&McMartin>
That "convert back into a string" would, however, be a new, different string.
21:33
<@Alek>
but you'd save it back to the same variable. XD
21:33
<&McMartin>
Ah, but that's not the point
21:33 * Alek isn't really seeing the point then
21:34
<&McMartin>
Then the variable is pointing to the new value, and the old one is "lost"
21:34
<&McMartin>
So, the issue you're missing here is aliases
21:34
<&McMartin>
With arrays...
21:34
<&McMartin>
a = [1, 2, 3]
21:34
<&McMartin>
b = a
21:34
<&McMartin>
a => [1, 2, 3]
21:34
<&McMartin>
b[0] = 4
21:34
<&McMartin>
a => [4, 2, 3]
21:34
<@Alek>
huh!
21:35
<&McMartin>
But that trick doesn't work with strings, because if you did the thing you describe, b would no longer be the same underlying string
21:35
<@Alek>
I bet this gets mentioned within a few more paragraphs. <_<
21:35
<&McMartin>
Likely >_>
21:35
<&McMartin>
ISTR you did some adventuring in this space already with Python before you left :)
21:36
<&McMartin>
So hopefully you'll get a moment where the model all snaps together in your head at once, with your old stuff and the new explanations
21:37
<@Alek>
I tried, but didn't really get there because the needed stuff hadn't been covered yet and I was trying to do it with what I already knew, which wasn't suited to the task, I think.
21:37 * McMartin nods
21:37
<&McMartin>
Well, I guess part of this is to just keep the mystery alive in your head and see if it clears up
21:37
<&McMartin>
Aliasing is an issue I can talk about at length so if you've gone through the units and are still confused about how things are going on under the hood, I can probably help
21:37
<@Alek>
I do need to go back to python and finish it up, eventually.
21:37
<&McMartin>
... but probably only in evenings Pacific time ;)
21:38
<@Alek>
lol.
21:38
<@Alek>
that's fine.
21:39
<@Alek>
I think I'm good for now. no real questions at the moment.
21:39
<@Alek>
I'm taking it a bit at a time to not overstress, family stuff is pushing it.
21:44 * McMartin nods
22:18 Derakon_ [chriswei@Nightstar-5mvs4e.ca.comcast.net] has quit [Ping timeout: 121 seconds]
22:40 gizmore [kvirc@Nightstar-i5et5s.dip0.t-ipconnect.de] has quit [Ping timeout: 121 seconds]
22:41 gizmore [kvirc@Nightstar-l2ftk6.dip0.t-ipconnect.de] has joined #code
22:56 Kindamoody|afk is now known as Kindamoody
23:11 catalyst [catalyst@Nightstar-bt5k4h.81.in-addr.arpa] has joined #code
23:47 Kindamoody is now known as Kindamoody[zZz]
23:59 himi [sjjf@Nightstar-v37cpe.internode.on.net] has quit [Ping timeout: 121 seconds]
--- Log closed Wed Jul 27 00:00:22 2016
code logs -> 2016 -> Tue, 26 Jul 2016< code.20160725.log - code.20160727.log >

[ Latest log file ]