Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Call-coalton-function bug/awkwardness #1042

Closed
Izaakwltn opened this issue Jan 12, 2024 · 7 comments
Closed

Call-coalton-function bug/awkwardness #1042

Izaakwltn opened this issue Jan 12, 2024 · 7 comments

Comments

@Izaakwltn
Copy link
Collaborator

Note: This is probably less of a bug and more of an instance of awkward behavior that should be documented.

Calling a Coalton function with call-coalton-function only works if the called function is defined in a separate coalton-toplevel.

(defpackage #:ccf-bug
  (:use #:coalton
        #:coalton-prelude))

(in-package #:ccf-bug)

(coalton-toplevel
  (define (square1 x)
    (* x x))

  ;; this errors, undefined variable: ccf-bug::square1
  (define (print-square1 x)
    (lisp String (x)
      (cl:format cl:nil "square printed: ~a" (call-coalton-function square1 x)))))


(coalton-toplevel
  (define (square2 x)
    (* x x)))

;; this works because they're in separate toplevels
(coalton-toplevel
  (define (print-square2 x)
    (lisp String (x)
      (cl:format cl:nil "square printed: ~a" (call-coalton-function square2 x)))))

call-coalton-function is currently wholly omitted from coalton-lisp-interop.md. I'm happy to add documentation, especially if this is determined to be the working behavior of the call-coalton-function.

Also, it's probably been discussed, but none of the Coalton-Lisp bridge functions are documented in the reference, and I feel like they're very much part of the Coalton workflow. I can make a separate issue if others agree.

@stylewarning
Copy link
Member

Regarding your last sentence, yes please do make a separate issue.

@eliaslfox
Copy link
Collaborator

That is the expected behavior.

Also you don't need call-coalton-function when calling a top-level coalton function.

@Izaakwltn
Copy link
Collaborator Author

Sounds good, thanks for looking this over.

I'll weave some of these cases/behavior into the interop docs.

One last case/question: When calling a top-level coalton function with a parameter in lisp, is the example below the ideal/preferred/expected syntax:

(coalton-toplevel
  (define (cube1 x)
    (* x (* x x)))

  (define (print-cube1 x)
    (lisp String (x)
      (cl:format cl:nil "cubed: ~a" (coalton (cube1 (lisp Integer () x)))))))

I figured the main advantage to call-coalton-function is to avoid this syntax.

@eliaslfox
Copy link
Collaborator

You can just call it directly:

(define (print-cube1 x)
    (lisp String (x)
      (cl:format cl:nil "cubed: ~a" (cube1 x))))

The point of call-coalton-function is to allow calling a potentially curried function.

@Izaakwltn
Copy link
Collaborator Author

I'm afraid that solution doesn't work on my machine, though maybe it's something in my implementation.

Compiling

  (define (print-cube1 x)
    (lisp String (x)
      (cl:format cl:nil "cubed: ~a" (cube1 x))))

Returns the error

style-warning: 
    The function CUBE1 is called with one argument, but wants exactly two.
    --> PROGN DEFUN PROGN SB-IMPL::%DEFUN SB-IMPL::%DEFUN 
    --> SB-INT:NAMED-LAMBDA FUNCTION THE PROGN BLOCK THE LET VALUES 
    ==>
      1

Fixing that warning by wrapping it in coalton:

(define (print-cube1 x)
    (lisp String (x)
      (cl:format cl:nil "cubed: ~a" (coalton (cube1 x)))))

Returns

error: 
    during macroexpansion of (COALTON (CUBE1 X)). Use
    COMMON-LISP:*BREAK-ON-SIGNALS* to intercept.
    
     error: Unknown variable
      --> COALTON (/private/var/tmp/slimepQIMm3):1:16
       |
     1 |  (COALTON (CUBE1 X))
       |                  ^ unknown variable
    
    --> PROGN DEFUN PROGN SB-IMPL::%DEFUN SB-IMPL::%DEFUN 
    --> SB-INT:NAMED-LAMBDA FUNCTION THE PROGN BLOCK THE LET VALUES 
    ==>
      1
    
  style-warning: 
    The variable X is defined but never used.
    --> PROGN DEFUN PROGN SB-IMPL::%DEFUN SB-IMPL::%DEFUN 
    --> SB-INT:NAMED-LAMBDA FUNCTION THE PROGN BLOCK THE 
    ==>
      (LET ((CCF-BUG::X CCF-BUG::X-302))
        (VALUES
         (FORMAT NIL "cubed: ~a" (COALTON:COALTON (CCF-BUG::CUBE1 CCF-BUG::X)))))

Which is how I ended up at my example above, (coalton (cube1 (lisp Integer () x))).

I'd like to reiterate, I'm not really poking into this because I need this personally, or even that I think it's broken. There are enough ways to get around this with little hacks, but I just want to clarify behavior so that it can be defined clearly in documentation.

@eliaslfox
Copy link
Collaborator

eliaslfox commented Jan 18, 2024

Oh yeah. If your function has type class constraints then you can't call it from lisp, you need to use the coalton macro. call-coalton-function wouldn't work either in this case.

The "fix" is to define:

(coalton-toplevel
  (declare cube1-integer (Integer -> Integer))
  (define cube1-integer cube1))

Then cube1-integer can be called directly from lisp.

@Izaakwltn
Copy link
Collaborator Author

Awesome, thank you, that one works perfectly.

I'm going to add a few of these cases to the docs in the next few days, thank you for the clarity!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants