[racket-users] Can I hide a method in a trait?

2020-08-13 Thread Siyuan Chen
Dear all,

Just imagine, suppose we have two traits `spots-trait` and `stripes-trait`,
they are developed independently.

These two traits depend on a "private" method `helper` respectively.

See following code:

```
(define spots-trait
  (trait
   (define/public (helper)
 (println "spots-trait helper"))
   (define/public (eat/spots)
 (println "spots-trait eat/spots")
 (helper))
   ))

(define stripes-trait
  (trait
   (define/public (helper)
 (println "stripes-trait helper"))
   (define/public (eat/stripes)
 (println "stripes-trait eat/spots")
 (helper))
   ))
```

Now I want to define the 3rd trait (called `spots+stripes-trait`),
something like:

```
(define spots+stripes-trait
  (trait-sum spots-trait stripes-trait))
```

But this is impossible because there is a name colliding (the`helper`
method).

One workaround to this problem is "renaming":

```
(define spots+stripes-trait
  (trait-sum
   (trait-rename spots-trait helper helper/spots)
   (trait-rename stripes-trait helper helper/stripes)))
```

This works.

But is this a good way? (It looks not very "hygienic")

Note that the `helper` is just a "private" method, it should not be visible
to its user.

PS: It seems that Racket does not support private members for traits.
Although I don't think "private members" is a good idea because private
members are not friendly to unit-testing.

An alternative way is moving the private `helper` method to a different
trait, splitting the original responsibilities across multiple traits
leading to simpler, better designs.

See following code:

```
(define spots-helper-trait
  (trait
   (define/public (helper)
 (println "spots-helper-trait helper"))
   ))

(define spots-core-trait
  (trait
   (inherit helper)
   (define/public (eat/spots)
 (println "spots-core-trait eat/spots")
 (helper))
   ))

(define stripes-helper-trait
  (trait
   (define/public (helper)
 (println "stripes-trait helper"))
   ))

(define stripes-core-trait
  (trait
   (inherit helper)
   (define/public (eat/stripes)
 (println "stripes-core-trait eat/spots")
 (helper))
   ))
```

Now I can redefine `spots-trait` and `stripes-trait`.

My attempt is `trait-sum` the `spots-core-trait` and `spots-helper-trait`
first, and then "hide" the `helper`, something like:

```
(define spots-trait
  (trait-hide ;; <-- attempt to hide `helper` method (Not real Racket)
   (trait-sum spots-core-trait spots-helper-trait)
   helper))

(define stripes-trait
  (trait-hide ;; <-- attempt to hide `helper` method (Not real Racket)
   (trait-sum stripes-core-trait stripes-helper-trait)
   helper))

(define spots+stripes-trait
  (trait-sum spots-trait stripes-trait))
```

Is this possible in Racket?

The advantage of "hiding" is that

1. The `spots-trait` now only exposes its interface `eat/spots `, we can
easily reuse it in other traits without worrying about name colliding (the
name `helper` is very commonly used, imo) .

2. Compared with the "renaming" solution, "hiding" looks more "hygienic",
because it can avoid further name colliding.

PS: I admit this example may be a bit weird, but you can think of "spots"
and "stripes" as some sort of service traits.

Thanks.

Best regards,
Siyuan Chen

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/CAHWTsY%3DBCOBXc%2BL9JkR%2BCnS2htKadRnrkpx4w6oUMS5OhdOEtw%40mail.gmail.com.


Re: [racket-users] Can Racket implement LockedMagicDoor example of MIXEDJAVA?

2020-08-13 Thread Siyuan Chen
 Dear Ryan,

No, traits can contain fields, which are mutable, so a trait can manage
> state.
>

Thanks, I tested it.

You are right, traits can manage states.

Right, one trait cannot override another's definitions. One thing you
>  could do instead is use `trait-exclude` to remove the definition of
>  `needed-item` from `secure-trait` before linking a trait (like
>  `locked-needed-trait`, but using `define/public` instead of
>  `define/override`) that defines the `needed-item` method. But if you do
>  that, I think there's no way to chain to the original definition. (I
>  haven't tried any of this, but that's what I get from the docs.)
>

Yes, "remove the definition of  `needed-item` from `secure-trait`" can
solve the name colliding problem, but there's no way to chain to the
original definition, because `needed-item` has been excluded.

Anyway, that feature sounds maybe more dangerous than worthwhile.
>

Do you mean the feature of MIXEDJAVA?

Why do you think it is dangerous?

As the paper says:

> We consider this an advantage of mixins
> because it enforces the maxim "program to an interface, not
> an implementation".

See the following code:

```
(define door<%> (interface () can-open can-pass))
(define secure-mixin
  (mixin (door<%>) (secure-door<%>) ; Inherit from a interface instead of
implementation
(super-new)
(define/public (needed-item)
  (println "secure-mixin needed-item")
  #f)
(define/override (can-open p)
  (println "secure-mixin can-open")
  (define item (needed-item))
  (cond
((not (send p has-item item)) (printf "You don't have the Key ~v\n"
item)
  #f)
(else (printf "Using Key... ~v\n" item)
  (super can-open p
))
```

Ideally, the developer of `secure-mixin` only needs to care about the
interface of the super-class, not the implementation.

Notice that the interface `door<%>` only has `can-open`  and `can-pass`, no
`needed-item`, so even if the implementation class of the `door<%>` has a
method with the same name (`needed-item`),  it should not cause conflicts.

It seems to be a good idea, IMO.

But if you know that you might want to apply the secure mixin multiple
>  times with different needed items, then there are other ways to write
>  that code. One is to parameterize the mixin by the needed item directly:
>

That's a good idea.

It is something like "prefer composition over inheritance" or "dependency
injection".

Another is to parameterize `secure-mixin` over the *name* of the  auxiliary
> hook method, using `define-member-name` etc. That avoids the  problem of
> needing the same *name* to refer to different "slots" at  different points
> in time; instead, just use two different names
>

Nice.

Racket supports parameterizing identifiers in a `class`, that's an amazing
feature!

Best regards,

Siyuan Chen


On Thu, Aug 13, 2020 at 6:28 AM Ryan Culpepper 
wrote:

> On Wed, Aug 12, 2020 at 7:19 PM Siyuan Chen  wrote:
>
>> Dear Ryan,
>>
>> Thanks for your solution, it works nicely!
>>
>> But I still have some questions:
>>
>> For this particular problem of LockedMagicDoor, we can use `trait` to
>> solve the `mixin` problem, but can we use the same method for more general
>> problems?
>>
>> Since traits and mixins are essentially different, they may not mimic
>> each other...
>>
>> IMO, they are at least 2 differences:
>>
>> 1. Traits can not have states, but mixin can.
>>
>>For example, if the `secure-trait`,  `locked-needed-trait`, and
>> `magic-needed-trait` have mutable states, then you can not use `trait`.  (A
>> workaround may be to convert `trait` to `mixin` first and then compose a
>> "state" mixin. But this will cause the same problem of name colliding,
>> because `mixin` does not support renaming)
>>
>
> No, traits can contain fields, which are mutable, so a trait can manage
> state.
>
> 2. `trait-sum` is symmetric, it does not support overriding.
>>
>>For example, in your solution:
>>
>>```
>>(define locked-mixin
>>  (trait->mixin
>>   (trait-rename (trait-sum secure-trait locked-needed-trait)
>> needed-item needed-item/locked)))
>>```
>>
>>To construct `locked-mixin`, you `trait-sum` the  `secure-trait` and
>>  `locked-needed-trait`, but what if there is a default implementation of
>> `needed-item` in the `secure-trait`? We even hope the `locked-needed-trait`
>> can delegate to `super`, something like:
>>
>>```
>>(defin

Re: [racket-users] Can Racket implement LockedMagicDoor example of MIXEDJAVA?

2020-08-12 Thread Siyuan Chen
Dear Ryan,

Thanks for your solution, it works nicely!

But I still have some questions:

For this particular problem of LockedMagicDoor, we can use `trait` to solve
the `mixin` problem, but can we use the same method for more general
problems?

Since traits and mixins are essentially different, they may not mimic each
other...

IMO, they are at least 2 differences:

1. Traits can not have states, but mixin can.

   For example, if the `secure-trait`,  `locked-needed-trait`, and
`magic-needed-trait` have mutable states, then you can not use `trait`.  (A
workaround may be to convert `trait` to `mixin` first and then compose a
"state" mixin. But this will cause the same problem of name colliding,
because `mixin` does not support renaming)

2. `trait-sum` is symmetric, it does not support overriding.

   For example, in your solution:

   ```
   (define locked-mixin
 (trait->mixin
  (trait-rename (trait-sum secure-trait locked-needed-trait)
needed-item needed-item/locked)))
   ```

   To construct `locked-mixin`, you `trait-sum` the  `secure-trait` and
 `locked-needed-trait`, but what if there is a default implementation of
`needed-item` in the `secure-trait`? We even hope the `locked-needed-trait`
can delegate to `super`, something like:

   ```
   (define locked-needed-trait
 (trait
  (define/override (needed-item)
(println "locked-needed-mixin neededItem")
(super needed-item  ;; We want to call super.
   ```

The key question is:

Does the current racket class system have the equivalent capabilities of
MIXEDJAVA?

More concretely, we know that Racket supports mixin, but Racket's `mixin`
is slightly different from MIXEDJAVA. This is because we seemingly can not
implement LockMagicDoor by using only `mixin-form` (Is this by design? I
heard that there are some historical origins of MIXEDJAVA and MzScheme).

But Racket supports two additional features, i.e.  `inner` and `trait`,
 which are not in MIXEDJAVA.

Consequently,  I'm curious about whether there is any design pattern in
Racket that can simulate the semantics of MIXEDJAVA ?

Thanks.

Best regards,
Siyuan Chen


On Tue, Aug 11, 2020 at 10:09 PM Ryan Culpepper 
wrote:

> I don't know of a way to solve that problem using the Racket class system
> alone, but here is a solution that uses traits instead, which allow you to
> rename the hook methods after the fact so they don't collide.
>
>   ;; 
>   (require racket/trait)
>
>   (define secure-trait
> (trait
>  (inherit needed-item)
>  (define/override (can-open p)
>(println "secure-mixin can-open")
>(define item (needed-item))
>(cond
>  ((not (send p has-item item)) (printf "You don't have the Key
> ~v\n" item)
>   #f)
>  (else (printf "Using Key... ~v\n" item)
>(super can-open p))
>
>   (define locked-needed-trait
> (trait
>  (define/public (needed-item)
>(println "locked-needed-mixin neededItem")
>the-key)))
>
>   (define magic-needed-trait
> (trait
>  (define/public (needed-item)
>(println "magic-needed-mixin neededItem")
>the-spell-book)))
>
>   (define locked-mixin
> (trait->mixin
>  (trait-rename (trait-sum secure-trait locked-needed-trait)
>needed-item needed-item/locked)))
>
>   (define magic-mixin
> (trait->mixin
>  (trait-rename (trait-sum secure-trait magic-needed-trait)
>needed-item needed-item/magic)))
>   ;; 
>
> Ryan
>
>
> On Sun, Aug 9, 2020 at 11:12 PM Siyuan Chen  wrote:
>
>> Hi all,
>>
>> Recently I read the paper "Classes and Mixins" by Matthew Flatt, Shriram
>> Krishnamurthi and Matthias Felleisen.
>>
>> In this paper, the authors presented MIXEDJAVA.
>>
>> In MIXEDJAVA,
>>
>>> A programmer implements mixins in exactly the same
>>> way as a derived class, except that the programmer cannot
>>> rely on the implementation of the mixin's superclass, only
>>> on its interface. We consider this an advantage of mixins
>>> because it enforces the maxim "program to an interface, not
>>> an implementation".
>>>
>> It is very close to the mixin form in Racket, because we can specific
>> interface in the mixin form:
>>
>> ```
>> (mixin (interface-expr ...) (interface-expr ...)
>>   class-clause ...)
>> ```
>>
>> In Chapter 3, they also introduced an example (a maze adventure game, I
>> called it LockedMagicDoor) which uses the system.
>>
>> My question is:
>>
>> Is it possible to i

[racket-users] Can Racket implement LockedMagicDoor example of MIXEDJAVA?

2020-08-09 Thread Siyuan Chen
uot;)
  the-spell-book)
))
```

But still failed:

; class*: superclass already contains method
;   superclass: #
;   method name: needed-item

See https://gist.github.com/chansey97/264d3435a8f506153709cc9804227fdf

PS: I also tried `overment` and `augment` for the `needed-item` in
`secure-mixin`, but failed as well (although the error messages are
different).


IMO, it seems that `Inner` can be used to simulate the behavior of
MIXEDJAVA, but I don't know how to do it.

Notice that in the paper, "Super and Inner — Together at Last!" by David S.
Goldberg, Robert Bruce Findler and Matthew Flatt, the authors originally
used `beta` and `java` to mark the methods, no need `pubment` a method
first. In that model, it may not be conflicting (just a very immature
opinion).

So can we use the `Inner` to simulate the behavior of MIXEDJAVA?


Another question:

In MIXEDJAVA, there is a `view` concept, which is very powerful.

Can we get the corresponding equivalent in Racket?

Very thanks.


Best regards,

Siyuan Chen

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/CAHWTsYnZCbRt2U%2Bt7JQPNt7rBNQAwSy8_4ycUqNkQ23ZOdncvQ%40mail.gmail.com.


Re: [racket-users] Is it possible to simulate FEXPRs in Racket?

2020-06-09 Thread Siyuan Chen
Hi Jens,

Thank you for telling me that Racket does not support capture and extend
environments.

So that I can change direction.

Hi all,

I found that Guile has a function called `local-eval`, which can be used to
simulate FEXPRs.

see
https://www.gnu.org/software/guile/manual/guile.html#index-local_002deval

I implemented do-notation by `local-eval`.

```
;guile 2.2.3
(use-modules (ice-9 local-eval))
(use-modules (ice-9 match))
(use-modules (srfi srfi-9))

(define-record-type Just
  (make-Just x)
  Just?
  (x Just-x))

 (define-record-type Nothing
  (make-Nothing)
  Nothing?)

(define (extends-env env var-name value)
  (local-eval
   `(let ((,var-name ,value))
  (the-environment)) env))

(define (do env binds return)
  (match binds
[()
 (begin
   (local-eval return env))]
[((var e) rest-binds ...)
 (begin
   (match (local-eval e env)
 [($ Nothing) (make-Nothing)]
 [($ Just x) (do (extends-env env var x) rest-binds return)])
   )]))

(define (bigger-than-two n)
  (if (> n 2)
  (make-Just n)
  (make-Nothing)))

(display
 (do (the-environment)
(list '[x (bigger-than-two 4)]
  '[y (bigger-than-two 5)])
'(make-Just (+ x y
```

I was surprised that it works.

PS: The code above can be compiled and run in guile 2.2.3.
You can test it at https://rextester.com/l/scheme_online_compiler, if
someone interested,

Best regards,
Siyuan Chen


On Mon, Jun 8, 2020 at 12:23 AM Jens Axel Søgaard 
wrote:

> Den søn. 7. jun. 2020 kl. 14.09 skrev Siyuan Chen :
>
> Unfortunately, this code doesn't work, because it lacks two functions,
>> `get-current-env` and `extends-env`.
>>
>
> These are not available since static lexical scope makes it possible for
> the compiler to determine where
> a variable is stored at compile time. Therefore an explicit environment is
> not needed.
> (See "early binding" vs "late binding").
>
>
>> Is there any way to work around this issue?
>>
>
>
>> I have searched Racket's document. Racket has namespaces that are very
>> similar to the environment here.
>>
>> But it seems that `current-namespace` can not get binding (e.g. Just) and
>> `namespace-set-variable-value!` is a mutable function which is not suitable
>> as well.
>>
>
> Namespaces are "environment-like" but contain only top-level variables.
>
> Could someone give me some advice?
>> Or we can modify the code above to make it work in Racket.
>>
>
> Since this for educational/fun use and not practical, I suggest using a
> Scheme interpreter where the environments
> are explicit.  Then you can easily add `get-current-env` and `extends-env`
> yourself.
>
> One option is the interpreter page LiSP (Lisp in Small Pieces) where an
> interpreter for fexprs is discussed
> with full working code.
>
> /Jens Axel
> https://racket-stories.com
>
>
>
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/CAHWTsYkD7i2ctsc-rAYrjjKBNKBBd8rQvqni2%2B-F%3DHV8PHtWiw%40mail.gmail.com.


[racket-users] Is it possible to simulate FEXPRs in Racket?

2020-06-07 Thread Siyuan Chen
Dear all,

** Note that this question is not for practical programming, but just play
for fun.**

I want to implement Maybe monad in Racket.

The following code works.

```
(struct Just (a)
  #:transparent)
(struct Nothing ()
  #:transparent)

(define (bigger-than-two n)
(if (> n 2)
(Just n)
(Nothing)))

(define (>>= mx f)
  (match mx
[(Nothing) (Nothing)]
[(Just x) (f x)]))


(>>= (bigger-than-two 4)
  (λ (x)
(>>= (bigger-than-two 5)
  (λ (y)
(Just (+ x y))
```

The disadvantage of this implementation is that it doesn't look nice.

So I want to implement do notation.

One way to implement do notation is by using Lisp macro, but I don't want
to use macro.

There is an alternative of Lisp macros called FEXPRs, see
https://en.wikipedia.org/wiki/Macro_(computer_science)#Early_Lisp_macros

> Early Lisp macros
> Before Lisp had macros, it had so-called FEXPRs, function-like operators
whose inputs were not the values computed by the arguments but rather the
syntactic forms of the arguments, and whose output were values to be used
in the computation. In other words, FEXPRs were implemented at the same
level as EVAL, and provided a window into the meta-evaluation layer. This
was generally found to be a difficult model to reason about effectively.

More information, see https://en.wikipedia.org/wiki/Fexpr

Therefore, I attempt to use fexpr to simulate macro.

The following code simulates fexpr by `eval` to implement Maybe monad.

```
(struct Just (a)
  #:transparent)
(struct Nothing ()
  #:transparent)

(define (bigger-than-two n)
(if (> n 2)
(Just n)
(Nothing)))

(define (do env binds return)
  (match binds
[nil
 (eval return env)]
[`((,var ,e) ,rest-binds)
 (match (eval (e env))
   [(Nothing) (Nothing)]
   [(Just x) (do (extends-env env var x) rest-binds return)])]))

(do (get-current-env)
(list '[x (bigger-than-two 4)]
  '[y (bigger-than-two 5)])
  '(Just (+ x y)))
```

Unfortunately, this code doesn't work, because it lacks two functions,
`get-current-env` and `extends-env`.

Is there any way to work around this issue?

I have searched Racket's document. Racket has namespaces that are very
similar to the environment here.

But it seems that `current-namespace` can not get binding (e.g. Just) and
`namespace-set-variable-value!` is a mutable function which is not suitable
as well.

Could someone give me some advice?
Or we can modify the code above to make it work in Racket.

Very thanks.

Best regards,
Siyuan Chen

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/CAHWTsYnhHCwg1gQuZVG%2BjnwLmnC3_8UK4L4n98JpTJ9PWePKxg%40mail.gmail.com.


Re: [racket-users] Is there any way to redefine printf in main.rkt ?

2019-04-01 Thread Siyuan Chen
Dear George,

I have just found a way to solve this problem.

Use (current-output-port out).

But still very thank you.


On Tue, Apr 2, 2019 at 1:30 AM George Neuner  wrote:

>
> On 4/1/2019 1:09 PM, Siyuan Chen wrote:
> > Dear George,
> >
> > This means we must modify these module code?
> >
> > For example:
> >
> > suppose in foo.rkt
> >
> > #lang racket
> > (provide ...)
> > (require ...)
> >
> > (define (my-func-1 x)
> > ...printf..)
> >
> > (define (my-func-2 x)
> >   ...printf..)
> >
> > It must be modified to this?
> >
> > #lang racket
> > (provide ...)
> > (require ...)
> >
> > (with-output-to-file 
> >(lambda ()
> >   (define (my-func-1 x)
> > ...printf..)
> >
> > (define (my-func-2 x)
> >   ...printf..)
> >))
> >
> > It seems not very convenient...
> >
> > Is it possible to temporarily change global output port?
> >
> > Thanks.
>
>
> Not exactly.  You don't need to encapsulate the function definitions -
> just the calls.  IT would be more like the following:
>
> #lang racket
> (provide ...)
> (require ...)
>
>(define (my-func-1 x)
> ...printf..)
>
> (define (my-func-2 x)
>...printf..)
>
>
> (with-output-to-file 
> (lambda ()
>(my-func-1 ...)
>(my-func-2 ...)
> ...
> ))
>
>
> But if that still is too heavyweight, the best solution is to run the
> program from the command line and redirect or tee the output into a
> file:  e.g.,
>
> racket [flags] program > file
> or
> racket [flags] program | tee file
>
> The exact flags to use depend on the specifics of your program (e.g., is
> it a script, is it a module, etc.):
>
> https://docs.racket-lang.org/reference/running-sa.html?q=command%20line#%28part._mz-cmdline%29
>
> Note: Windows doesn't have "tee", but you can do something similar with
> racket [flags] program > file 2>&1
>
> George
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.