alveric4 has quit [Read error: Connection reset by peer]
conta2 has joined #ruby
alveric4 has joined #ruby
blackmesa has quit [Quit: WeeChat 1.9.1]
duckpuppy has joined #ruby
<RickHull>
ok, I get it now; the print_3 example helped
<RickHull>
i don't think I've played with currying in ruby before
conta2 has quit [Ping timeout: 248 seconds]
darkmorph has quit [Ping timeout: 240 seconds]
<RickHull>
as far as usefulness -- it gives you more flexibility for structure and expression -- where you don't have to write your methods according to what data is available at a certain "layer" of the program?
<RickHull>
partial application? is that the term?
<RickHull>
at some layer, you can call a method that needs 3 args with the 2 available, and pass it upwards to get the 3rd arg
<dminuoso>
RickHull: Not exactly. You get the effect of it
_main_ has joined #ruby
<RickHull>
something like that?
<dminuoso>
RickHull: The idea is just this: every function takes exactly 1 argument.
duckpuppy has quit [Ping timeout: 248 seconds]
_main_ has quit [Read error: Connection reset by peer]
<dminuoso>
RickHull: But yes you use it exactly like that.
<RickHull>
i feel like there's a lazy evaluation win in there somewhere too
<RickHull>
where if you don't have this, you call the method and get the return value, because the program structure demands it
_main_ has joined #ruby
nicesignal has quit [Remote host closed the connection]
ur5us has joined #ruby
_main_ has quit [Read error: Connection reset by peer]
<RickHull>
but maybe we didn't need to do the work
<dminuoso>
RickHull: You can create usefulness functions. One favourite example is that of adding.
nicesignal has joined #ruby
<dminuoso>
Think you have some `defc :add { |a, b| a + b }`
__main__ has quit [Ping timeout: 240 seconds]
guardianx has joined #ruby
<dminuoso>
add(2) gives you an adder function back, namely one that adds 2 to whatever you pass it to
troys is now known as troys_
_main_ has joined #ruby
<dminuoso>
Or maybe an eq function such as: `defc :eq { |a, b| a == b }`. now to see whether an array includes something, you can do arr.filter(&eq(5))
<RickHull>
it's very hard to see why that is helpful
<dminuoso>
RickHull: Okay, what if you wanted something that `when added to 2, equals to 10`
<dminuoso>
then you do: arr.filter(&(eq(5) * add(2))
_main_ is now known as __main__
<dminuoso>
Here Proc#* denotes function composition (it constructs a new function, whose argument is passed to the right function, and the return value is then passed to the left function -> creating a pipeline)
ur5us has quit [Ping timeout: 248 seconds]
<dminuoso>
RickHull: But yeah, its often useful to just "partially apply" to give a preconstructed function with some arguments already set.
sucks has joined #ruby
sucks_ has joined #ruby
<RickHull>
if f(x) == x**2 and g(x) == x + 2. then f(x) * g(x) is f(g(x)) ?
<dminuoso>
RickHull: (f * g)(x) is f(g(x))
sucks has quit [Remote host closed the connection]
<RickHull>
ok
<dminuoso>
so `f after g`
<dminuoso>
RickHull: Now there's a lot more powerful things. One basic tool is that of `fmap`
<dminuoso>
RickHull: so instead of foo.map(&func) you could also say `fmap(func, foo)`
<Sparky2>
I'm confused
<dminuoso>
and if you dont apply it the entire way, something special happens: funcF = fmap(func). fmap has suddenly transformed your function from a normal one into one that can handle arrays
<RickHull>
dminuoso: that looks more like Elixir than ruby
<dminuoso>
RickHull: The magic lies in *not* applying that `foo` right away to gain intuition about whats happening.
<Sparky2>
My lesson is telling me I run irb like: >>> $ irb irb(main):001:0>
<Sparky2>
What have I missed?
<Sparky2>
never mind
_main_ has joined #ruby
<RickHull>
dminuoso: that sort of makes sense -- is fmap something ruby does today?
<dminuoso>
RickHull: No I implemented that myself (you can see it in the gist)
<RickHull>
and what about &func vs func ?
petto has joined #ruby
<dminuoso>
RickHull: Thats a ruby thing. Most of ruby core extends blocks (which for all intends and purposes are just functions)
<dminuoso>
*expects
<dminuoso>
So you have to explicitly convert your functions to blocks.
<RickHull>
yeah, ok
__main__ has quit [Ping timeout: 248 seconds]
<RickHull>
if I def foo, then I would do: func = method(:foo) # or similar?
_main_ is now known as __main__
<dminuoso>
RickHull: Let me cook up some working example
<RickHull>
i sort of get that func originally operates on scalars, which is why you can pass it to Enumerable#map]
<RickHull>
(sensibly)
<dminuoso>
RickHull: Yeah, now Enumerable#map does two steps and it hides that fact.
<dminuoso>
RickHull: Im splitting them into two. First lift the function from a function that transforms numbers to numbers, into a function that transforms arrays of numbers to arrays of numbers
<dminuoso>
For clarify of types, Ill do Number -> Bool into [Number] -> Bool in my example
jackjackdripper has quit [Quit: Leaving.]
<RickHull>
is there a literal sense where you pass an array as an arg to func?
<dminuoso>
That last line just wont work. Now the thing is, the array kind of has Integer in it, but it has additional structure so isOdd cant work with it.
<RickHull>
also, isOdd.(3)
<dminuoso>
RickHull: Indeed. I added type anotations, reload.
<RickHull>
yep, but you need the '.()' right?
<dminuoso>
Yeah
<RickHull>
anyways, not a problem :)
__main__ has quit [Read error: Connection reset by peer]
<dminuoso>
RickHull: reload.
__main__ has joined #ruby
<dminuoso>
RickHull: Now just accept that f in the type signature can be [] (in fact it can be a lot of other things too)
<RickHull>
makes sense
<RickHull>
but hard to see a win
<RickHull>
i mean, why not just Enumerable#map
hopsoft has quit [Quit: My MacBook has gone to sleep. ZZZzzz…]
<dminuoso>
RickHull: You have some module that operates on arrays
<dminuoso>
You cant change that code.
<dminuoso>
Or.. mm
<RickHull>
I believe there is a win, and I've tasted it before :)
<RickHull>
but I'm trying to put my finger on it
<dminuoso>
RickHull: Time to introduce a new type. Maybe. Maybe is kind of like Array, except its contrained to a max length of 1 okay?
<RickHull>
sure
dviola has joined #ruby
<RickHull>
also I've seen in some numerical libs, like numpy and such
<dminuoso>
And instead of writing [1] we say Just 1, and instead of writing [] we say Nothing.
<RickHull>
where the same functions operate on scalars, vectors, and matrices
<dminuoso>
fmap can work with that too.
<dminuoso>
RickHull: Or maybe you are doing something like this, this is a wonderful example!
<dminuoso>
instead what you do, is you use Maybe to denote that the value could exist or not.
<matthewd>
So you instead construct a whole new meta-language inside ruby, because that's less annoying
<RickHull>
LOL
<dminuoso>
Sparky2: infinite recursion probably
<RickHull>
Sparky2: you probably called a recursive function with no stopping condition
<matthewd>
Sparky2: The problem is inside the method
<RickHull>
yes, I am familiar with Maybe and Option types, though have hardly used them
<RickHull>
but I know the concept and understand the utility
<dminuoso>
RickHull: The idea is that you express function in terms of "the value exists", and fmap transforms it into a function that shortcircuits if its Nothing.
<dminuoso>
which you can pass to someone else, and they can just stuff a Maybe in there.
<dminuoso>
your responsibility is just building a function that can process maybe data, but you dont have the data, someone else does
petto has quit [Remote host closed the connection]
<matthewd>
Sparky2: I'm not going to debug this one line at a time.
<dminuoso>
or maybe that can process arrays. you use fmap to build such a function, and give it to someone else who needs to process arrays
<RickHull>
Sparky2: best to paste the entirety of the code
<Sparky2>
RickHull: I'll do some googling and see if I can work out what is going on
<RickHull>
dminuoso: one way to explain this as a win, is that you can write small functions that are obviously correct, yet flexible and composable enough to work in a larger system
<RickHull>
it helps isolation, in a sense
<RickHull>
?
<dminuoso>
RickHull: Exactly. Now you use functions to transform functions. And fmap is not just a wild transformation, it respects some very precise laws.
<dminuoso>
These laws lets you reason about program, and even better: it lets you rewrite programs according to those laws, without knowing what it doe.s
<dminuoso>
Or you can reason about certain parts, because the law tells you "this holds true because of the XXX laws"
orbyt_ has quit [Quit: My MacBook has gone to sleep. ZZZzzz…]
Dimik has quit [Ping timeout: 260 seconds]
<dminuoso>
RickHull: for example fmap has the following laws: (fmap f) * (fmap g) == fmap (g * f)
<dminuoso>
and given id = -> (e) { e }, `fmap id = id`
<ruby[bot]>
RickHull: # => undefined method `reverse' for nil:NilClass (NoMethodError) ...check link for more (https://eval.in/897789)
<RickHull>
oh, hm
cagomez has quit [Remote host closed the connection]
<dminuoso>
RickHull: And thats the problem with &., you have to use it every step of the way
<RickHull>
yeah
<matthewd>
dminuoso: But how is that different from .() ?
Xiti` has quit [Quit: Xiti`]
<RickHull>
so can we build a better &. pretty simply?
Xiti has joined #ruby
<matthewd>
&. is a call syntax that gives special treatment to the no-value object, and applies the operation for any other 'just' value
<dminuoso>
matthewd: &. does not compare to .()
<RickHull>
i am thinking mostly in terms of the effect of handling nil without blowing up
<RickHull>
through a sequence of operations
<dminuoso>
The closest analogy will be Proc#>= in my upcoming library
Technodrome has quit [Quit: My MacBook has gone to sleep. ZZZzzz…]
<dminuoso>
Errr, Maybe#=>
<dminuoso>
Maybe#>=
guardianx has quit []
<matthewd>
It swaps the order around, sure.. but it seems awfully close to Maybe semantics
duckpuppy has joined #ruby
<RickHull>
how do you know that your fmap impl satisfies the laws? write tests?
<dminuoso>
RickHull: Usually its easy to just reason about it and see that they hold true.
<Sparky2>
No way... I was getting an error because I had a comment shifted one space to the left
<RickHull>
I suppose this relates to provably correct and the ML realm
<dminuoso>
RickHull: Yeah, but you really dont have to go that far. In haskell you have a special bonus, that allows you to only prove one of these two laws, and get the other for free.
<dminuoso>
So you usually just prove fmap id = id.
<dminuoso>
(Which is usually trivial that you dont even need to write or draw anything)
<dminuoso>
in ruby you dont, so you have to prove it for both cases
iceden has quit [Ping timeout: 246 seconds]
<dminuoso>
RickHull: also in all fairness, I implemented fmap twice. Once on BasicObject, and once on Kernel.
iceden has joined #ruby
<dminuoso>
that allows you to do container.fmap(func) or `fmap func` depending on whether you intend is just applying that function the container or lifting the function instead.
<dminuoso>
Just regarding your concern why this would be useful
cdg has joined #ruby
cdg has quit [Remote host closed the connection]
<RickHull>
i would think the latter is more general
<RickHull>
does the former do anything the latter can't?
<dminuoso>
Nope
<RickHull>
just convenience?
<dminuoso>
RickHull: Convenience.
<RickHull>
I'd be tempted to define the former in terms of the latter
<RickHull>
and only have one impl and 2 signatures
<dminuoso>
RickHull: a.fmap(b) == fmap b a
<dminuoso>
and oops on that haskellism. *fmap(b, a)
__main__ has quit [Read error: Connection reset by peer]
<RickHull>
so the win for defc is arity enforcement?
duckpuppy has quit [Ping timeout: 268 seconds]
<dminuoso>
RickHull: arity enforcement, ability to use methods as first-class objects, and currying for stepwise application
<dminuoso>
(that second is also used, so if you dont pass any arguments, you get a function object back)
hopsoft has quit [Ping timeout: 248 seconds]
<matthewd>
I'd say it's arity deferral rather than enforcement
_main_ is now known as __main__
<dminuoso>
matthewd: Oh I just meant as opposed to procs (which was your original tip)
<matthewd>
RickHull: The win is basically that this turns useful argumenterrors into confusing nomethoderrors
<RickHull>
what's a concrete example of using methods as first-class objects compared to standard ruby?
<matthewd>
Just Like Haskell™
<RickHull>
yeah, I'm still pretty fuzzy on this, grasping
<dminuoso>
matthewd: lens.rb:94:in `block in <module:Kernel>': wrong number of arguments (given 3, expected 2) (ArgumentError)
<matthewd>
dminuoso: "spicy" was a joke, but I do think I'd name this closer to define_method rather than def -- that's the signature it matches
<dminuoso>
not sure what you mean
<RickHull>
I don't quite grok defc where name is nil/non-nil
<baweaver>
defn
<baweaver>
mmmmm lispy
jenrzzz_ has joined #ruby
<dminuoso>
RickHull: That's just a dirty hack to enable singleton methods with that style
<RickHull>
defun just sucks the fun right out of it
jrafanie has quit [Quit: My MacBook has gone to sleep. ZZZzzz…]
<matthewd>
dminuoso: If you give a curried method too few arguments then call something on its result, you'll get a NoMethodError because the half-curried proc doesn't respond to gsub (or whatever)
jottr has quit [Ping timeout: 248 seconds]
jenrzzz has quit [Ping timeout: 240 seconds]
<matthewd>
dminuoso: If you give a curried method too many parameters, one at a time, via separate .(x).(y), you'll get a NoMethodError because the string you got back doesn't respond to call
yeticry_ has joined #ruby
<dminuoso>
matthewd: Ohh, if you use separate .(x).(y) yeah fair enough
<matthewd>
"The idea is just this: every function takes exactly 1 argument." ;)
<dminuoso>
matthewd: the problem is just syntax.
yeticry has quit [Ping timeout: 240 seconds]
<dminuoso>
matthewd: in haskell I could just do `a b c`. from that perspective a(1,2) is fine too as long as you dont see it as one application, but applying a to 1, and then applying its result to 2 :P
<dminuoso>
I guess `a 1, 2` makes this a bit easier on the eyes
<dminuoso>
in fact in a weird way the comma makes this grouping obvious!
enterprisey has joined #ruby
<matthewd>
And Haskell would also treat `a b c` as a ~NoMethodError if a was "only expecting one argument"
<matthewd>
(Granted, at compile time)
sucks_ has quit [Ping timeout: 240 seconds]
<dminuoso>
You'd get some couldn't match expected type ‘a -> b’ with actual type ‘c’
<dminuoso>
With enough information to identify the spot where you obviously tried to apply a value to a value
rajno has quit [Quit: Leaving]
<matthewd>
"enough information to identify the spot where you obviously tried to apply a value to a value" is what the ruby 'NoMethodError: <some value>#call' + backtrace gives you too
<matthewd>
Ah okay, it does actually "decode" the 3-for-2, which you're losing in the ruby equivalent
<RickHull>
one common problem in enterprisey applications, particularly db-backed, is it's painful to check everything for nil. assumptions get made, and NPEs result from a schema change or missing field
<RickHull>
I think with the right approach, a lot of this pain can go away, but some of it just gets pushed around to something else that's hard to manage
mikecmpbll has quit [Quit: inabit. zz.]
<matthewd>
Yeah, I think that's my argument: [given it's not the language-native form] this is just a different way of explicitly coding null-awareness into everything you write
yeticry has joined #ruby
marr has quit [Ping timeout: 248 seconds]
yeticry_ has quit [Ping timeout: 240 seconds]
tlaxkit has quit [Quit: ¡Adiós!]
helpa has quit [Remote host closed the connection]
<greensleeves>
It is for parsing man pages and auto generating bash completion files, but somehow it is doing an incomplete job, in that it's not fetching all the options from man pages
<greensleeves>
matthewd: I am unable to understand the regex, would appreciate some help
<matthewd>
greensleeves: Right. But which part do you not understand?
noobineer has joined #ruby
noobineer has quit [Max SendQ exceeded]
kies has quit [Ping timeout: 240 seconds]
jenrzzz_ has quit [Ping timeout: 240 seconds]
<greensleeves>
I think the expression is looking for --<option>, -<option> but since it is only parsing a part of the man page (it returns an incomplete list of options) I am thinking if it is parsing the entire page
<matthewd>
greensleeves: Also, do you have an example of what it does/doesn't match?
<greensleeves>
Okay
<matthewd>
At a glance, the $ on lines 10 and 14 don't sound right to me
duckpuppy has joined #ruby
shoogz has quit [Quit: shoogz out]
Sparky2 has quit [Ping timeout: 260 seconds]
duckpuppy has quit [Ping timeout: 248 seconds]
<elomatreb>
I'm a little too tired to understand the regex, but a similar man page parsing script I worked with had a similar problem (only parsing out some of the options) and it turned out it was because it only looked at the options in one specific section
ledestin has quit [Quit: My MacBook has gone to sleep. ZZZzzz…]
<RickHull>
any regex longer than 10 characters should be commented (with //x) and have test cases
<RickHull>
there, I said it
tcopeland has joined #ruby
<RickHull>
the first thing I would do, when debugging a regex, is add comments and test cases ;)
<RickHull>
and as elomatreb implies, perhaps the regexen are fine and there is a problem with the outer logic
<elomatreb>
RickHull: Another thing that really helps user friendliness of regexess are named matching groups
Cohedrin has quit [Quit: My MacBook has gone to sleep. ZZZzzz…]
<matthewd>
This one seems pretty legible to me ¯\_(ツ)_/¯
<matthewd>
RickHull: `\A # starts with` -- are you one of those people who comments what `x = 1` does too? :|
<greensleeves>
matthewd: I think that was one problem, on lines 10 and 14. The regex is not able to fetch some options when I ran it for "man"
<greensleeves>
The rror it gave me was : <standard input>:981: warning [p 8, 1.8i, div `3tbd1,0', 0.0i]: cannot adjust line
Cohedrin has joined #ruby
<RickHull>
matthewd: \A is rather non-obvious in meaning
<greensleeves>
*error
<RickHull>
particularly given its \z counterpart
<RickHull>
it may as well be 0x92
<RickHull>
or w/e
<matthewd>
RickHull: Only if you assume the reader isn't familiar with regex syntax
<RickHull>
most people think ^ and $
<matthewd>
@foo is non-obvious if you're not familiar with ruby syntax, too
<greensleeves>
matthewd: it worked perfectly for man page for clock, it parsed through and got me all the options with the corrections on lines 10 and 14
sucks_ has joined #ruby
<bougyman>
@foo = bar is pretty obvious
<bougyman>
even if you aren't familiar with ruby
Cohedrin has quit [Read error: Connection reset by peer]
<matthewd>
bougyman: The assignment maybe, but not the meaning of @
<bougyman>
agree
<greensleeves>
matthewd: It gave me the above error for man page of man, and got me only a partial list
<matthewd>
greensleeves: It's really not a workable generic solution
<matthewd>
greensleeves: It only recognises particular layout of manpage, for a start
sucks has quit [Ping timeout: 240 seconds]
Cohedrin has joined #ruby
ur5us has joined #ruby
sucks has joined #ruby
quobo has quit [Quit: Connection closed for inactivity]
<greensleeves>
matthewd: oh, so it doesn't parse through the entire page in some cases. Where does it break?
<matthewd>
man pages are written to be read by humans, and are formatted inconsistently. A 10 line "parser" cannot reliably extract meaning.
tcopeland has quit [Quit: tcopeland]
sucks_ has quit [Ping timeout: 268 seconds]
shoogz has joined #ruby
shoogz has quit [Max SendQ exceeded]
Defenestrate has quit [Quit: Leaving]
ur5us has quit [Ping timeout: 240 seconds]
shoogz has joined #ruby
shoogz has quit [Max SendQ exceeded]
guacamole has joined #ruby
shoogz has joined #ruby
shoogz has quit [Max SendQ exceeded]
kryptoz has joined #ruby
shoogz has joined #ruby
shoogz has quit [Max SendQ exceeded]
shoogz has joined #ruby
shoogz has quit [Max SendQ exceeded]
orbyt_ has joined #ruby
Azure has quit [Quit: My MacBook has gone to sleep. ZZZzzz…]
ledestin has joined #ruby
ledestin has quit [Client Quit]
shoogz has joined #ruby
shoogz has quit [Max SendQ exceeded]
<greensleeves>
matthewd: okay. Can you suggest a way to perhaps extend this to extract all possible options in a given man page? One thing I noticed is it skips the Synopsis Section of the man page and goes to the Options section
<RickHull>
greensleeves: there is likely no simple fix. there is no spec for manpage output that allows it to be generally parseable. whoever wrote this was satisfied for the inputs it was tested against
<RickHull>
to proceed, you should debug it
<RickHull>
which means feeding it an input that has bad behavior
<RickHull>
and examining the program state.
<RickHull>
a simple way to do this is to add print statements
kryptoz has quit [Read error: Connection reset by peer]
kryptoz has joined #ruby
kculpis has joined #ruby
Azure has joined #ruby
mson has quit [Quit: Connection closed for inactivity]
_lyte_ has joined #ruby
kryptoz has quit [Read error: Connection reset by peer]
<RickHull>
for this particular program, that looks difficult. it's very terse bash/sh. L30 is the entry point for the main logic
sucks has quit [Read error: Connection reset by peer]
sucks has joined #ruby
<RickHull>
i'm not sure what `col -b` does when fed with various manpages
<RickHull>
but you could start there
kies has joined #ruby
cam27 has joined #ruby
<greensleeves>
RickHull: okay, shall try debugging it. I think col -b is for filtering. From man "-b Do not output any backspaces, printing only the last character written to each column position."
<RickHull>
yeah, I have no idea what that reverse line feed stuff all about. maybe having to do with manpage interactivity and scrollability
<RickHull>
the other thing I would do is: man foo | col -b > manfoo.txt
<RickHull>
and use that for the input to the parsing
yeticry has quit [Ping timeout: 248 seconds]
cdg has joined #ruby
yeticry has joined #ruby
gizmore|2 has joined #ruby
sucks has quit [Remote host closed the connection]
gizmore has quit [Ping timeout: 248 seconds]
cdg has quit [Ping timeout: 258 seconds]
sucks has joined #ruby
alfiemax has quit [Ping timeout: 260 seconds]
d^sh has quit [Ping timeout: 248 seconds]
duckpuppy has joined #ruby
d^sh has joined #ruby
Cohedrin has quit [Quit: My MacBook has gone to sleep. ZZZzzz…]
sucks has quit [Remote host closed the connection]
duckpuppy has quit [Ping timeout: 248 seconds]
<matthewd>
greensleeves: The best idea is really to write a custom completion handler for the command you're interested in. There's a reason this is not the normal approach.
jenrzzz has joined #ruby
Xiti has quit [Ping timeout: 240 seconds]
cdg has joined #ruby
nofxx__ has joined #ruby
nofxx_ has quit [Ping timeout: 248 seconds]
_lyte_ has quit [Remote host closed the connection]
Silthias has quit [Read error: Connection reset by peer]
Silthias has joined #ruby
ledestin has joined #ruby
epochwolf has quit [Ping timeout: 250 seconds]
br0d1n has quit [Quit: Leaving]
kryptoz has joined #ruby
epochwolf has joined #ruby
guacamole has quit [Quit: My face has gone to sleep. ZZZzzz…]