mirror of
https://github.com/vale981/emacs-jupyter
synced 2025-03-06 07:51:39 -05:00
Monad things
This commit is contained in:
parent
1191153ca4
commit
d6b6bd60ce
4 changed files with 125 additions and 11 deletions
|
@ -432,9 +432,7 @@ fields:
|
|||
|
||||
;;; Request object definition
|
||||
|
||||
(cl-defstruct (jupyter-request
|
||||
(:constructor nil)
|
||||
(:constructor jupyter-request))
|
||||
(cl-defstruct jupyter-request
|
||||
"Represents a request made to a kernel.
|
||||
Requests sent by a client always return something that can be
|
||||
interpreted as a `jupyter-request'. It holds the state of a
|
||||
|
@ -451,9 +449,11 @@ types to callback functions a client should call."
|
|||
(id (jupyter-new-uuid) :read-only t)
|
||||
(type nil :read-only t)
|
||||
(content nil :read-only t)
|
||||
(client nil :read-only t)
|
||||
(time (current-time) :read-only t)
|
||||
(idle-p nil)
|
||||
(last-message nil)
|
||||
(messages nil)
|
||||
(inhibited-handlers nil)
|
||||
(callbacks nil))
|
||||
|
||||
|
|
|
@ -537,14 +537,19 @@ kernel whose kernelspec if SPEC."
|
|||
|
||||
;;; Shutdown and interrupt a kernel
|
||||
|
||||
;; FN is already a monadic function in the IO context of Emacs
|
||||
|
||||
(cl-defmethod jupyter-shutdown-kernel ((client jupyter-kernel-client))
|
||||
"Shutdown the kernel CLIENT is connected to.
|
||||
After CLIENT shuts down the kernel it is connected to, it is no
|
||||
longer connected to a kernel."
|
||||
(when-let* ((kernel (and (slot-boundp client 'kernel)
|
||||
(oref client kernel))))
|
||||
(jupyter-wait-until-idle (jupyter-send client :shutdown-request))
|
||||
(jupyter-shutdown kernel)))
|
||||
(jupyter-do (jupyter-io client)
|
||||
(jupyter-after
|
||||
(jupyter-idle (jupyter-request "shutdown"))
|
||||
(lambda (req)
|
||||
;; Ensure the Emacs representation of the kernel also knows
|
||||
;; that the kernel's process has been shutdown.
|
||||
(jupyter-shutdown (jupyter-kernel client))))))
|
||||
|
||||
(cl-defmethod jupyter-interrupt-kernel ((client jupyter-kernel-client))
|
||||
"Interrupt the kernel CLIENT is connected to."
|
||||
|
@ -878,10 +883,12 @@ user. Otherwise `read-from-minibuffer' is used."
|
|||
(read-from-minibuffer prompt))
|
||||
(with-timeout-unsuspend timeout-spec)))
|
||||
(quit ""))))
|
||||
(unwind-protect
|
||||
(jupyter-send client :input-reply :value value)
|
||||
(when (eq password t)
|
||||
(clear-string value)))
|
||||
(jupyter-do (jupyter-io client)
|
||||
(jupyter-bind
|
||||
(jupyter-request :input-reply :value value)
|
||||
(lambda (_req)
|
||||
(when (eq password t)
|
||||
(clear-string value)))))
|
||||
value)))
|
||||
|
||||
(defalias 'jupyter-handle-input-reply 'jupyter-handle-input-request)
|
||||
|
|
|
@ -136,6 +136,22 @@ actions/queries:
|
|||
('hb nil)
|
||||
(_ (error "Unhandled IO: %s" args))))))
|
||||
|
||||
;; Kernel -> IO Kernel-IO
|
||||
(cl-defmethod jupyter-connect ((kernel jupyter-kernel))
|
||||
;; Any -> IO Kernel-IO
|
||||
(jupyter-launch kernel)
|
||||
(jupyter-return (jupyter-io kernel)))
|
||||
|
||||
;; Client -> IO Client
|
||||
(cl-defmethod jupyter-connect ((client jupyter-kernel-client))
|
||||
;; Any -> IO Client-IO
|
||||
(lambda (_)
|
||||
(let ((io (jupyter-io (jupyter-kernel client))))
|
||||
(jupyter-return
|
||||
(lambda (&rest args)
|
||||
(let ((jupyter-current-client client))
|
||||
(apply io args)))))))
|
||||
|
||||
(defun jupyter-io (thing)
|
||||
"Return a function that can be used to perform I/O with THING.
|
||||
The function takes arguments like (TYPE ARGS...) where TYPE is a
|
||||
|
|
91
jupyter-monads.el
Normal file
91
jupyter-monads.el
Normal file
|
@ -0,0 +1,91 @@
|
|||
(require 'thunk)
|
||||
|
||||
(defun jupyter-return (value)
|
||||
(declare (indent 0))
|
||||
(lambda (_io) value))
|
||||
|
||||
;; Adapted from `thunk-delay'
|
||||
(defmacro jupyter-return-thunk (&rest body)
|
||||
(declare (indent 0))
|
||||
`(let (forced val)
|
||||
(lambda (_io)
|
||||
(unless forced
|
||||
(setf val (progn ,@body))
|
||||
(setf forced t))
|
||||
val)))
|
||||
|
||||
(defconst jupyter-io-nil (jupyter-return nil))
|
||||
|
||||
(defvar jupyter-current-io
|
||||
(lambda (&rest args)
|
||||
(error "Unhandled IO: %s" args)))
|
||||
|
||||
;; TODO: Keep track of the function bound to a io-value such that the
|
||||
;; function is accessible
|
||||
(defun jupyter-bind (io-value fn)
|
||||
"Bind MVALUE to MFN."
|
||||
(declare (indent 1))
|
||||
(pcase (funcall io-value jupyter-current-io)
|
||||
((and req (cl-struct jupyter-request client)
|
||||
(let jupyter-current-client client))
|
||||
(funcall fn req))
|
||||
(`(timeout ,(and req (cl-struct jupyter-request)))
|
||||
(error "Timed out: %s" (cl-prin1-to-string req)))
|
||||
(`,value (funcall fn value))))
|
||||
|
||||
(defun jupyter--do (&rest mfns)
|
||||
(cl-reduce
|
||||
(lambda (io-value mfn)
|
||||
(jupyter-bind io-value mfn))
|
||||
mfns :initial-value jupyter-io-nil))
|
||||
|
||||
(defmacro jupyter-do (io &rest forms)
|
||||
(declare (indent 1))
|
||||
`(let ((jupyter-current-io ,io))
|
||||
(jupyter--do ,@forms)))
|
||||
|
||||
(defun jupyter-after (io-value fn)
|
||||
(declare (indent 1))
|
||||
(lambda (io)
|
||||
(jupyter-bind io-value fn)))
|
||||
|
||||
(defun jupyter-idle (io-req)
|
||||
(jupyter-after io-req
|
||||
(lambda (req)
|
||||
(jupyter-return
|
||||
(if (jupyter-wait-until-idle req) req
|
||||
(list 'timeout req))))))
|
||||
|
||||
;; MsgType -> MsgList -> (IO -> Req)
|
||||
;; (IO -> Req) represents an IO monadic value. IO Req
|
||||
(defun jupyter-request (type &rest content)
|
||||
"Return an IO action that sends a `jupyter-request'.
|
||||
TYPE is the message type of the message that CONTENT, a property
|
||||
list, represents.
|
||||
|
||||
See `jupyter-io' for more information on IO actions."
|
||||
(declare (indent 1))
|
||||
(setq type (intern (format ":%s-request"
|
||||
(replace-regexp-in-string "_" "-" type))))
|
||||
(lambda (io)
|
||||
(let* ((req (make-jupyter-request
|
||||
:client jupyter-current-client
|
||||
:type type
|
||||
:content content))
|
||||
(ch (if (memq type '(:input-reply :input-request))
|
||||
:stdin
|
||||
:shell))
|
||||
(id (jupyter-request-id req)))
|
||||
(letrec ((handler
|
||||
(lambda (event)
|
||||
(pcase (car event)
|
||||
((and 'message (let `(,channel . ,msg) (cdr event))
|
||||
(guard (string= id (jupyter-message-parent-id msg))))
|
||||
(cl-callf nconc (jupyter-request-messages req)
|
||||
(list msg))
|
||||
(when (jupyter--message-completes-request-p msg)
|
||||
(setf (jupyter-request-idle-p req) t)
|
||||
(jupyter-send io 'remove-handler handler)))))))
|
||||
(jupyter-send io 'message ch type content id)
|
||||
(jupyter-send io 'add-handler handler)
|
||||
req))))
|
Loading…
Add table
Reference in a new issue