Thanks @sorawee I’ve added that to the wiki: https://github.com/racket/racket/wiki/Chromebook-Install\|https://github.com/racket/racket/wiki/Chromebook-Install
@liquidcloud9 has joined the channel
I have a question about point-free style with multi parameters.
Suppose I have a binary operator add: (define (add x y)
(+ x y)) Now I want to define add3. One way to achieve this purpose is: (define (add3 x y z)
(add x (add y z))) But this is not point-free style. What I want is something like this: (define add3-with-point-free
(compose add (bimap identity add))) Is this to be possible in Racket?
BTW, Haskell can do this kind of thing. For example: add :: (Int, Int) -> Int
add (x, y) = x + y
add3WithPointFree :: (Int, (Int, Int)) -> Int
add3WithPointFree = add . bimap id add
add3WithPointFree (1, (2, 3)) -- 6 The drawback of Haskell is that the function’s parameters are default currying, so the solution above is not very general. For example, we usually expect to call a function as following: add3WithPointFree 1 2 3 instead of add3WithPointFree (1, (2, 3)) Fortunately, Racket does not have this problem because the function’s parameters in Racket can be regarded as multi-values.
I think @notjack’s https://docs.racket-lang.org/point-free/ might be helpful here?
You could certainlyy write those Haskell functions in Racket, but bimap would be a bit weird
@sorawee I have tested his library, it seems not suitable here. (define add3-with-point-free
(compose add (join identity add))) ;; failed to compille.
it definitely compiles, but it doesn’t work
note that your Haskell code relies on the fact that (a,b,c) == (a,(b,c)) in haskell
without that, the code is much more awkward
@samth This because + is a monoid, but if you want ((a,b),c), you can write: add . bimap add id
IMO, Racket is very suitable for bimap or muti-map, because the parameters of Racket are not curried by default. It can enhance composability.
what your bimap is doing is going from 3 values to 2, in a way that would be odd in racket
(bimap identity add) :: Int x Int x Int -> Int x Int
you can write that, but it would be very odd
(define ((bimap f g) a b c) (values (f a) (g b c)))
note that with that definition, (bimap add identity) produces an error
@samth Yes, but it should work, right? There seems no ambiguity here.
no, I don’t think this version of bimap makes any sense
3-tuples do not have a canonical bifunctor
I agree. The name bimap is not good.
Maybe we can give it a new name.
But what should it do?
@samth May be something like (pseudocode): (define ((join2 f g) . args)
(let*-values ([(f-args args) (compute-args f args)]
[(g-args args) (compute-args g args)])
(values (apply f f-args) (apply g g-args))))
I’d rather do that pointfully I think
fancy-app is about the most point freedom I can read, in my experience
(which would be why I haven’t worked on point-free in a long time)
I just wrote a version of join2 : (define ((join2 f g fn) . args)
(let*-values ([(f-args g-args) (split-at args fn)])
(values (apply f f-args) (apply g g-args))) )
(define (add x y)
(+ x y))
(define add3-with-point-free
(compose add (join2 identity add 1))) ; <--- need fill 1 for identity
(define add3-with-point-free-2
(compose add (join2 add identity 2))) ; <--- need fill 2 for add
(add3-with-point-free 1 2 3) ;; 6
(add3-with-point-free-2 1 2 3) ;; 6 The drawback is it needs to fill in the number of parameters.
yup
I think that’s not a drawback, it’s an advantage
how many parameters something takes is useful information that I want to know when I’m reading code
the real advantage is it saves me from having to think up good names for them
I just installed fancy-app . Why the example code failed in my REPL? (+ 1 (+ _ 2)) Told me ; +: contract violation
; expected: number?
; given: #<procedure:...ncy-app/main.rkt:28:27>
; argument position: 2nd
; other arguments...:
; 1
where did you find that example?
That example is to show how it doesn’t work in that case.
@samdphillips Oh, thanks.
It would be nice, if it can work in that case.
I think a plain lambda would be better there
It’s eventually about readability. (compose f g h) conveys the intent better than (lambda (x) (f (g (h x)))), so use it there. But if you need to perform gymnastic to flip argument order etc, no one is going to understand the code. It’s really not worth it (besides as a fun puzzle challenge)
to make that example work, you’d need some sort of delimiter to say where the the lambda goes. but at that point, it’s basically just a different syntax for lambda
drracket sometimes starts misbehaving? and i get a visual artifact where the - (minus) character sometimes flashes or stays invisible, unless it’s a feature and i pressed a key combination by accident? edit: the font size was too small. i thought it was the same size from always, but i might have pressed the decrease font size twice. (although it had happened to me before i thought it was only decreased once)