themetaschemer / malt

Machine Learning Toolkit accompanying The Little Learner by Daniel P. Friedman and Anurag Mendhekar
MIT License
212 stars 25 forks source link

ext1 and +-0-0 are not friends #39

Closed sporkl closed 1 year ago

sporkl commented 1 year ago

Getting some strange behaviour when I combine +-0-0 and ext1. When I define an add1-like function with +-0-0, use ext0 on it, then the resulting function seems to do nothing.

(define f-0-0 (lambda (t) (+-0-0 t 1)))
(define f (ext1 f-0-0 0))
(f 1) ; would expect to be 2, but returns 1
Captura de Pantalla 2023-07-20 a la(s) 5 48 53 p  m

This happens with both the nested-tensors representation and the flat-tensors representation, but NOT the learner representation.

sporkl commented 1 year ago

The same sort of thing happens with multiplication, I suspect it is the same for others as well.

> (define f-0-0 (lambda (t) (*-0-0 t 2)))
> (define f (ext1 f-0-0 0))
> (f 2)
2
themetaschemer commented 1 year ago

With nested and flat representations, the argument to ext1/2 must be a primitive (constructed with a prim1 or prim2 function). The result of an ext1/2 is also a prim, so any extended function can be directly extended. Unfortunately, plain lambda's won't. This is discussed in the appendix B where these restrictions are introduced.

themetaschemer commented 1 year ago

See also Section 5.5 in https://docs.racket-lang.org/malt/Extended_Functions.html

sporkl commented 1 year ago

My bad, I forgot about that. Thanks, and apologies for the trouble.

Perhaps it could be useful to throw an error when ext1 or ext2 is called with a non-prim? I would be up to work on this.

themetaschemer commented 1 year ago

The problem with that is that there is no test prim? test. Prims are currently implemented as lambda's. In order to have a prim? test, you'll have to use Racket's callable struct instances, which we decided not to pursue in the book's implementations.

sporkl commented 1 year ago

I was thinking that a prim? test could be constructed by checking if a function can be passed ρ-function and ∇-function without error. Though it might be too inelegant.

themetaschemer commented 1 year ago

One scheme standard way of doing it would be to maintain a global parameter that holds all known primitives that are constructed from a standard prim constructor. Then you can check for the presence of this constructor in the global parameter as "prim?". Otherwise, trying to look into the prim would pretty much be inelegant in every form and would rely on underlying representation.