mflatt
2020-12-7 12:27:12

You’re right that you need to learn about phase and procedural macros instead of pattern-matching macros. For example, on line 96 of “ffiREPL.rkt”, you want the for (should be something like for/list) to happen at expand time, not run time. So, you’ll need to use define-syntax instead of define-syntax-rule. Also, you’ll need to learn a little about scope and non-hygienic macros; the define-lib-func introduced by the use macro will never be visible, because it’s introduced by the macro (which means that only other code inroduced by the same macro invocation can see the binding).


ben.knoble
2020-12-7 14:13:50

@ben.knoble has joined the channel


phanthero
2020-12-7 14:27:28

Can anyone help me convert this to a foldl/foldr or for/fold/for/foldr : (define mapin (make-hash)) (define (make-thing2 lst) (cond [(null? (cdr lst)) (define my-index 0) (hash-set! mapin (car lst) my-index) (add1 my-index)] [else (define my-index (make-thing2 (cdr lst))) (hash-set! mapin (car lst) my-index) (add1 my-index)])) (make-thing2 '(d c b a)) (println mapin)


phanthero
2020-12-7 14:27:56

I am just scared of folding, but I know I can grasp it somehow


laurent.orseau
2020-12-7 14:46:23

Does this do what you want? (for/hash ([x (reverse '(d c b a))] [idx (in-naturals)]) (values x idx))


gknauth
2020-12-7 14:59:45

Folding is scary in the real world, but in functional programming we can fold forever (mostly). https://youtu.be/65Qzc3_NtGs


phanthero
2020-12-7 15:03:10

I think that’s it, thanks


laurent.orseau
2020-12-7 15:04:50

Always use a paper that implements proper tail-call optimization when folding it!


phanthero
2020-12-7 15:07:13

I have actually actively been avoiding fold and friends because I have built up no intuition on how to use it


phanthero
2020-12-7 15:07:24

If anyone has any good articles or blogs that explain it, let me know


phanthero
2020-12-7 15:07:34

I’ll try to look up some as well


sorawee
2020-12-7 15:20:17

The way I think about fold is that it’s just a regular for loop with functional update rather than imperative update


sorawee
2020-12-7 15:24:09

So let’s talk about functional update vs imperative update first.

In, say, Python, you might write:

x = 0 x = x + 1 x = x + 2 x = x + 3 This mutates the existing x for each statement.

In functional programming, you don’t mutate existing variables.

(define x 0) (define x* (+ x 1)) (define x** (+ x* 2)) (define x*** (+ x** 3))


sorawee
2020-12-7 15:25:53

You can express the above computation using for

sum = 0 for x in [1, 2, 3]: sum += x In functional programming, this could be similarly expressed using (for/)fold.

(for/fold ([sum 0]) ([x '(1 2 3)]) (+ sum x))


laurent.orseau
2020-12-7 15:27:28

@phanthero Though you could also write (let* ([x 0] [x (+ x 1)] [x (+ x 2)] [x (+ x 3)]) ....) That’s called “shadowing”: each ‘new’ x uses the previous x in its definition, then shadows it.


laurent.orseau
2020-12-7 15:28:00

There’s still no mutation involved, and the compiler will know how to optimize such cases.


phanthero
2020-12-7 15:37:01

Thank you @sorawee and @laurent.orseau, I think I understand it much better now!


lupino8211
2020-12-7 18:28:06

@mflatt, thank you very much! I updated repo You mean I can’t make define-lib-func globally visible even with non-hygienic macros?


lupino8211
2020-12-7 20:35:00

I guess I’m in deep need of code review…


phanthero
2020-12-7 21:02:14

You know how there’s a second that gives you the second element of a list? Is there something similar for a function that returns multiple values and you only want the second one?


soegaard2
2020-12-7 21:03:12

(compose second list->values)



sorawee
2020-12-7 22:52:39

How does this work? And I don’t think list->values is in the standard library.


sorawee
2020-12-7 22:53:33

@phanthero not sure if I understand your question. Do you mean, you want to implement ??? such that

(define (f) (values 1 2)) (??? (f)) returns 2?


soegaard2
2020-12-7 22:55:06

Did I miss something? (I’ll admit I didn’t test it). True, that it isn’t in the standard library - but it is short definition using using call-with-values..


soegaard2
2020-12-7 22:56:40

Oh… I did miss something. It’s values->list but that’s not a simple function.


sorawee
2020-12-7 22:57:18

Yeah, I think you will need a macro. A function won’t do it


soegaard2
2020-12-7 22:57:44

Agree.


sorawee
2020-12-7 22:57:52

If that’s the case, the answer is no. You can’t solve this problem by writing a function


sorawee
2020-12-7 22:58:06

But you can write a macro


sorawee
2020-12-7 22:58:25

E.g.,

(define (f) (values 1 2)) (define (extract-second* f) (call-with-values f (λ (a b . whatever) b))) (define-syntax-rule (extract-second x) (extract-second* (λ () x))) (extract-second (f))


cdep.illabout_slack
2020-12-8 00:22:58

I’ve been trying to use Racket this year for Advent of Code. However, I’m coming from Haskell, and I feel somewhat frustrated trying to code in a dynamic language.

I’m wondering what sort of things people do “in the real world” when writing Racket.


cdep.illabout_slack
2020-12-8 00:33:10

From briefly reading over the documentation, I can see a couple possibilities (although keep in mind I am a super beginner, so I definitely could have missed something):

  1. Use contracts. It looks like the standard library makes heavy use of contracts (which is pretty nice btw), but the section of the Racket guide on contracts suggests that same-module contracts (with define/contract) can be really slow, especially for functions called in a loop. From reading the guide, I get the feeling that it is discouraging define/contract. Although when doing Advent of Code, I’d really want contracts on all (or most of) the functions in one module.
  2. Use typed racket. I haven’t really looked into this. I don’t really have any idea of how popular typed racket is compared to normal racket. Do most people use typed racket when writing “actual code”? I haven’t gotten this impression from the Racket guide.
  3. Suck it up and write more tests. The module+ test thing makes it really easy to write tests basically inline, but I feel like the contract system or a type system would also be beneficial. There are tons of things that are easy for a type system to catch that are annoying to write tests for.
  4. Don’t do anything. Just get used to working in a dynamic language. (I guess I don’t really consider this an option, but I’d be interested to hear from anyone that thinks this is the correct approach.)

samdphillips
2020-12-8 00:37:19

As you are just doing Advent of Code I would recommend doing 1 and 3.


cdep.illabout_slack
2020-12-8 00:39:04

@samdphillips You’re suggesting that define/contract isn’t slow enough to give me any sort of problem in the Advent-of-Code-style problems?

Would your suggestion be different if I was actually trying to use Racket in some sort of professional manner? (E.g. on a large project, with a big team, with some sort of performance goals, etc)


sorawee
2020-12-8 00:40:05

Another option is between 1 and 4. Write contract unofficially as a comment. There won’t be a check for you programmatically, but it serves as a documentation.


samdphillips
2020-12-8 00:40:05

Yes and yes,


samdphillips
2020-12-8 00:41:28

If you are using Racket professionally, you would probably write more tests and use contracts at major module boundaries. You may potentially move code to Typed Racket as the program evolves.


sorawee
2020-12-8 00:41:51

Oh, I guess “between 1 and 3” is more appropriate


cdep.illabout_slack
2020-12-8 00:42:07

Hmm, I hadn’t really considered this, but now that you mention it, I don’t know how helpful it would be in practice.


cdep.illabout_slack
2020-12-8 00:43:21

I don’t really feel like it makes it any “easier” to program, in the same way that a type system or contract system makes it “easier” to program.


cdep.illabout_slack
2020-12-8 00:43:41

Although I agree it is an improvement over just not doing anything!


cdep.illabout_slack
2020-12-8 00:47:03

@samdphillips Okay, that makes sense. So on a big project, more tests for things within modules, and then contracts for inter-module stuff.

At some point I’ll have to play around with typed racket, but for now I’ll probably just go with your suggestion of define/contract and tests.



cdep.illabout_slack
2020-12-8 00:49:56

@sorawee Thanks, that is basically what I was imagining.


cdep.illabout_slack
2020-12-8 00:50:30

I guess the reason they used define here instead of define/contract is that they didn’t want to take the performance hit?


sorawee
2020-12-8 00:50:49

yeah


sorawee
2020-12-8 00:51:51

define/contract could also be very bad especially for recursive functions, since it will check the contract for every (recursive) call.


samdphillips
2020-12-8 00:51:55

Although you can write Typed Racket code from the beginning it really shines (IMO and by design) when you want to take an untyped Racket program and make it a bit more resilient.


sorawee
2020-12-8 00:52:12

Even worse, it could turn a tail recursion into a non tail recursion


sorawee
2020-12-8 00:52:33

That’s why contract is usually used at the module boundary


cdep.illabout_slack
2020-12-8 01:00:40

Ah, I see. Missing out on tail recursion could definitely be really bad.


cdep.illabout_slack
2020-12-8 01:01:37

Oh, huh, I guess I had thought that people would just write things from the beginning in Typed Racket.


yilin.wei10
2020-12-8 01:14:19

@cdep.illabout_slack I’ve come from a typed language (mostly Scala, but Haskell and a few others as well) and been using Racket for ~6 months now.


yilin.wei10
2020-12-8 01:16:06

At the beginning I was mimicking the Haskell/Scala code structures. They sort of (?) work, but feel really clunky.


yilin.wei10
2020-12-8 01:20:01

I found myself resorting to macros a lot more - in a similar way that you’d define a tagless final or initial DSL; but the composition feels like it’s based on forms rather than types.


yilin.wei10
2020-12-8 01:22:12

A really interesting example is something like https://docs.racket-lang.org/threading/index.html coming from Scala. I would have never thought to use a macro for it, but a newtype and a typeclass


yilin.wei10
2020-12-8 01:31:54

There are a few observations which I found quite surprising though; I didn’t have too much of an issue inferring the types of variables within the function as much as I thought I would because of the naming scheme.


samth
2020-12-8 01:40:48

I think you should try making a simple example of what you’re trying to do, that doesn’t feature extra syntax or the ffi


samth
2020-12-8 01:42:11

define/contract doesn’t check on the recursive call


sorawee
2020-12-8 01:49:18

wat


sorawee
2020-12-8 01:49:25

you are absolutely right, wow.


sorawee
2020-12-8 01:50:32

what about mutual recursion?


samth
2020-12-8 01:50:48

I think we had this conversation yesterday or something, but define/contract is a contract between the function and the rest of the module


samth
2020-12-8 01:51:09

So other functions get the contracted version


sorawee
2020-12-8 01:51:15

Makes sense


samdphillips
2020-12-8 01:51:32

This is a good description on how it can work in practice https://felleisen.org/matthias/manifesto/sec_full.html


samdphillips
2020-12-8 01:51:49

It’s part of a larger paper about the design of Racket


sorawee
2020-12-8 01:52:22

Oh, OK, I think I confused this with Pyret lol


cdep.illabout_slack
2020-12-8 02:02:56

Thanks, I’ll check this out.


cdep.illabout_slack
2020-12-8 02:05:44

Thanks for the advice. I’ll have to check out the threading library to get a feel for how these types of things are done in Racket.