
It’s great! Thanks @notjack

Good to know,

Why no flip function in the Racket base library? see https://docs.racket-lang.org/reference/procedures.html I don’t find flip function. (flip means flipping two arguments of functions when evaluating)

It’s rarely needed. In the past I have seen xcons
defined as (define (xcons d a) (cons a d))
.

most of the time when I would have used a flip function, what I really wanted was for the function I’m flipping to have a better order to its arguments in the first place

(looking at you, cons
)

I don’t think it is rarely need. For example, I am writing a threading functions like this
(define (compose-flip g f)
(compose f g))
(define (~>> arg list-of-funcs)
((foldr compose-flip identity list-of-funcs) arg))
;; Then I can call this:
(~>> 0
(list add1
add2
product3
product4))
Note that the function compose-flip
is defined by myself.
It would be nice, if base library can provide flip
directly.

If you are programming in the point free style, I see, that you will need it.

@soegaard2 Racket is a multi-paradigm language:wink:

I have another question: The following two examples, which one is better?
1st: (define (~>>-foldl arg list-of-funcs)
((foldl compose identity list-of-funcs) arg))
(~>>-foldl 0
(list add1
add2
product3
product4))
2nd: (define (compose-flip g f)
(compose f g))
(define (~>>-foldr arg list-of-funcs)
((foldr compose-flip identity list-of-funcs) arg))
(~>>-foldr 0
(list add1
add2
product3
product4))
Note that: 1st using foldl
and do not need flip
2nd using foldr
but need a custom flip
I prefers the 2nd one, because when executing it seem no need to extend the stack. But is there any way to profile this kind of thing in Racket? (to confirm this idea)
For example, To compare factorial
and factorial-iter
, we can using (trace factorial)
(define (factorial n)
(if (= n 1)
1
(* n (factorial (- n 1)))))
(trace factorial)
(factorial 6)
output is
>(factorial 6)
> (factorial 5)
> >(factorial 4)
> > (factorial 3)
> > >(factorial 2)
> > > (factorial 1)
< < < 1
< < <2
< < 6
< <24
< 120
<720
720
(define (factorial n)
(fact-iter 1 1 n))
(define (fact-iter product counter max-count)
(if (> counter max-count)
product
(fact-iter (* counter product)
(+ counter 1)
max-count)))
(trace fact-iter)
(fact-iter 1 1 6)
>(fact-iter 1 1 6)
>(fact-iter 1 2 6)
>(fact-iter 2 3 6)
>(fact-iter 6 4 6)
>(fact-iter 24 5 6)
>(fact-iter 120 6 6)
>(fact-iter 720 7 6)
<720
720
Is this trace
(or something like that) can be used to profile ~>>
which I defined above? Thanks.


@franci.dainese Thanks, will try it.

Interesting perspective. The let
variants have always behaved exactly as I expected. Occasionally, define
has not behaved as I expected. There was one particularly frustrating example that I can’t recall at the moment, and I remember thinking I should probably make a note of it, but then I realized there was no point since the let
family did exactly what I wanted.

If the list of functions is known ahead of time, you can use the <https://docs.racket-lang.org/threading/index.html#%28part..How___works%29|Threading Macros package. > (Maybe already familiar, but I love it.)

@maueroats Yes. threading-macro is great. This function I defined just a toy function. Actually, I think should reverse
list when need flip
in folding.

Can I define a internal define
in a test-suite
?
I’m writing a parsing-library, the following is my code structure: #lang racket
(provide (all-defined-out))
;; main code
...
;; test code
(module+ main
(require rackunit rackunit/text-ui)
(define parsing-tests
(test-suite
"Tests for basic parsing"
(define (try-three)
(define (g x y z)
(list x z))
(g (try-item) (try-item) (try-item)))
(check-equal? (parse try-three (string->list "abcdef")) '(#t (#\a #\c) (#\d #\e #\f)))
(check-equal? (parse try-three (string->list "ab")) '(#f ()))
))
(run-tests parsing-tests)
)
But compiled error: > define: not allowed in an expression context This because test-suite
is a expression, define
can not be allowed in an expression. So I have to lift (define (try-three) ...
to the top of module main
.
But as you see, the try-three
is just a util function for tests of “basic parsing”, I want to define it in the testsute
. Could someone give me a suggestion? Very thanks.

Or what’s the convention of writing this kind of Racket’s tests?

I’ve yet to use test-suite
so having nested defines of functions hasn’t been an issue.

Here’s an example: (module+ test
(require rackunit)
(exec-db-test
(λ (conn)
(define (foo n)
(+ n 7))
(check-equal? (foo 3) 10)
))
(check-equal? (format-full-name (build-sample-contact 3)) "Fred G. Flintstone")
)
Ignore exec-db-test
as that’s a custom function of mine.

Using module+ test ...
is convenient, then tests are automatically run with raco test file.rkt

Having said that, when testing, I often lift utility functions when I wouldn’t do the same in regular code.

@badkins Thanks, but I don’t understand your code. What’s the exec-db-test
?

As I mentioned above, that’s a custom function of mine that takes care of preparing a database connection so the test can make use of it.

You could just as easily use (let...
or something else for a scope.

@badkins You add all tests in the module test
and did not use test-suite
to group tests.

Correct, that was my point, test-suite
was not playing nice with define
for you, so I don’t think you need test-suite

But what I want is to split different test concepts by test-suite
(or something like that), not mix all tests in a module. What’s the convention of this sort of thing in Racket? By using submodules?

Racket provides a ton of ways to organize your code.

So you want to be able to run only a subset of your tests? I’m curious about what you’re trying to accomplish with test-suite

My colleagues often joke with me about the fact that I often answer the question “How do I …” with the answer of “with a function” :slightly_smiling_face:

> So you want to be able to run only a subset of your tests? I’m curious about what you’re trying to accomplish with test-suite
@badkins, yes. but… of course this is just to make the code look clean (because this is just a toy project). What I really want to know is the convention of Racket.

“clean” is in the eye of the beholder, but I personally have slightly different standards for normal code and test code. Having said that, organizing tests to reside w/in functions, or let scopes, or other scopes is clean to me. Your mileage may vary.

I found a solution: Using a let
inside test-suite, it works, although it make code drifted rightward a little bit… (module+ test
(require rackunit rackunit/text-ui)
(define parsing-tests
(test-suite
"Tests for parsing"
(let ()
(define (try-three)
(define (g x y z)
(list x z))
(g (try-item) (try-item) (try-item)))
(check-equal? (parse try-three (string->list "abcdef")) '(#t (#\a #\c) (#\d #\e #\f)))
(check-equal? (parse try-three (string->list "ab")) '(#f ()))
)
))
(run-tests parsing-tests)
)
Thanks:smile:

I think the let
variants should be avoided not because they behave unexpectedly, but because the behaviors they introduce are not worth keeping track of.

Actually I’d call this a bug. The test-suite
form should allow internal definitions.

I often need to initialize some variables in my let
blocks, so I don’t need to create an empty one just for organization. For example: (module+ test
(require rackunit rackunit/text-ui)
;; Tests for parsing
(let ([ s1 "abcdef" ]
[ s2 "ab" ])
(define (try-three)
(define (g x y z)
(list x z))
(g (try-item) (try-item) (try-item)))
(check-equal? (parse try-three (string->list s1)) '(#t (#\a #\c) (#\d #\e #\f)))
(check-equal? (parse try-three (string->list s2)) '(#f ()))
)
)
It doesn’t really make sense here for s1
and s2
, but I just did that as an example. I’m still not convinced of the value of test-suite
in this case.

You could reverse the list of functions instead of reversing the composition function’s argument order

Also you may be interested in the threading
package.

I had the opposite experience with define
- wasn’t worth thinking about how they behaved differently than expected i.e. no benefit to me. They’re also more verbose which I find more ugly than a slight indentation drift. I think what we have here is a different set of aesthetics which is to be expected :slightly_smiling_face:

how would you feel about var x = expr
syntax? as a wild hypothetical

If you had said, “I prefer define
because …” I doubt I would even have commented, but to say, “Please use define
… ” as a prescription doesn’t seem appropriate to me given it’s a preference.

regarding var x = expr
, in what context/language ? I mean, I prefer (let ([ x expr ]) ...
over var

I know there is work going on (at least I think it’s still happening) for Rhombus, but I just love Scheme, and one of the things I like about Scheme is let
- I find many aspects of it simply beautiful :slightly_smiling_face:

I think define
is a better default for the majority of racket users, and I find code with lots of nested let forms very frustrating to read. But you’re right, it’s pretty subjective.

It is subjective, and I certainly have code where I use define
similar to what you’re advocating - sometimes it does seem appropriate to me. One of the frustrating things about Ruby was some idiosyncrasies regarding lexical scope, and I think Scheme nailed it.

And I’m aware of the recommendations in the style guide, so I would abide by them when adding/editing core Racket code, vs. my own libraries, as a team player :slightly_smiling_face:

Consistency has its own beauty.