# Re: [racket-users] Defining algebraic data types?

```This is an unfortunately common pitfall -- if you instantiated N with
something that includes a dual number, then the type error would be
pointing to a real bug. If```
```
Sam

On Feb 5, 2018 7:26 AM, "HiPhish" <hiph...@openmailbox.org> wrote:

>
> 1) does not really capture it, and 2) is a proof of concept that hasn't
> been
> updated in almost a year. But it did give me a good idea: use Typed Racket
> and
> have the type system work for me.
>
>   (struct (N) D ([real : N] [dual : N]))
>   (define-type (Dual-Number N) (U N (D N)))
>
> Now a dual number is either an `N` (whatever an `N` is) or a pair of two
> `N`s.
> My next idea was to implement dual number multiplication like this:
>
>   (: dual-* (∀ (N) (→ (Dual-Number N) (Dual-Number N) (→ N N N) (→ N N N)
> (Dual-Number N))))
>   (define (dual-* d1 d2 * +)
>     (cond
>       [(and (D? d1) (D? d2))
>        (D (* (D-real d1)
>              (D-real d2))
>           (+ (* (D-real d1)
>                 (D-dual d2))
>              (* (D-dual d1)
>                 (D-real d2))))]
>       [(D? d1) (D (* d2 (D-real d1)) (* d2 (D-dual d1)))]
>       [(D? d2) (D (* d1 (D-real d2)) (* d1 (D-dual d2)))]
>       [else (* d1 d2)]))
>
> This captures the rule of multiplication of dual numbers in a generic way.
> For
> a particular type of dual number one then has to provide the meaning of
> `+` and
> `*` for the underlying `N`. So in case of dual vectors one could define
>
>     (define-type Dual-Vector (DualNumber (Vector3 Real)))
>     (: dual-vector-product (→ Dual-Vector Dual-Vector Dual-Vector))
>     (define (dual-vector-product dv1 dv2)
>       (dual-* dv1 dv2 vector3-* vector3-+))
>
> There is a problem with `dual-*` though: The predicate `D?` has type `(->
> Any
> Boolean : (D Any))`, and thus `D-real` and `D-dual` will return an object
> of
> type `Any` rather than `N`, even though the type annotation for `dual-*`
> makes
> it clear that the type would have to be `N`. Here is a simpler form of the
> function (obviously wrong math, I just want to get the types right):
>
>   (: dual-* (∀ (N) (→ (Dual-Number N) (Dual-Number N) (→ N N N) (→ N N N)
> (Dual-Number N))))
>   (define (dual-* d1 d2 * +)
>     (cond
>       [(D? d1)
>        (D
>          (D-real d1)
>          (D-dual d1))]
>       [else (D d1 d1)]))
>
> When I try to enter the module I get the following error:
>
>   > ,enter "source/types/dual-number.rkt"
>   source/types/dual-number.rkt:30:5: Type Checker: Polymorphic function
> `D1' could not be applied to arguments:
>   Argument 1:
>     Expected: N
>     Given:    Any
>   Argument 2:
>     Expected: N
>     Given:    Any
>
>   Result type:     (D N)
>   Expected result: (U (D N) N)
>
>     in: (D (D-real d1) (D-dual d1))
>
>
> On Sunday, February 4, 2018 at 3:26:28 PM UTC+1, Sam Tobin-Hochstadt wrote:
>>
>>
>> 1. Use struct subtyping to give a type that includes both kinds:
>>     (struct dual ())
>>     (struct quaternion dual (scalar vector))
>>     (struct dual-quaternon dual (real dual))
>>
>> 2. Use a library that supports algebraic data types, such as
>> https://pkgs.racket-lang.org/package/datatype
>>
>> Sam
>>
> --
> 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