Add (gnu gnunet monad).

* gnu/gnunet/monad.scm, examples/monad/identity.in: New files.
* configure.ac: Check for (guix monads).  Substitute
  examples/monad/identity.
* Makefile.am (MODULES): Add gnu/gnunet/monad.scm.
This commit is contained in:
Ludovic Courtès 2015-11-13 22:43:13 +01:00
parent d12167ab3c
commit 5a1748a48c
6 changed files with 188 additions and 0 deletions

4
.dir-locals.el Normal file
View File

@ -0,0 +1,4 @@
((nil . ((fill-column . 78)
(indent-tabs-mode . nil)))
(scheme-mode
. ((eval . (put 'run-with-scheduler 'scheme-indent-function 1)))))

1
.gitignore vendored
View File

@ -21,3 +21,4 @@ Makefile.in
/examples/publish
/examples/search
/examples/search-ns
/examples/monad/identity

View File

@ -20,6 +20,7 @@ MODULES = \
system/foreign/unions-read-write.scm \
system/foreign/unions.scm \
gnu/gnunet/common.scm \
gnu/gnunet/monad.scm \
gnu/gnunet/scheduler.scm \
gnu/gnunet/binding-utils.scm \
gnu/gnunet/container/metadata.scm \

View File

@ -34,6 +34,11 @@ AC_SUBST([guilemoduledir])
AC_CACHE_SAVE
GUILE_MODULE_AVAILABLE([have_guix_monads], [(guix monads)])
if test "x$have_guix_monads" != "xyes"; then
AC_MSG_ERROR([(guix monads) module could not be found])
fi
PKG_CHECK_MODULES([GNUNETUTIL], [gnunetutil])
PKG_CHECK_MODULES([GNUNETFS], [gnunetfs])
PKG_CHECK_MODULES([GNUNETIDENTITY], [gnunetidentity])
@ -57,4 +62,6 @@ AC_CONFIG_FILES([examples/publish], [chmod +x examples/publish])
AC_CONFIG_FILES([examples/search], [chmod +x examples/search])
AC_CONFIG_FILES([examples/search-ns], [chmod +x examples/search-ns])
AC_CONFIG_FILES([examples/monad/identity], [chmod +x examples/monad/identity])
AC_OUTPUT

View File

@ -0,0 +1,47 @@
#!@GUILE@ \
-e (@\ (gnunet-identity)\ main) -L . -s
!#
;;;; Copyright © 2015 Ludovic Courtès <ludo@gnu.org>
;;;;
;;;; This program is free software: you can redistribute it and/or modify
;;;; it under the terms of the GNU General Public License as published by
;;;; the Free Software Foundation, either version 3 of the License, or
;;;; (at your option) any later version.
;;;;
;;;; This program is distributed in the hope that it will be useful,
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;;;; GNU General Public License for more details.
;;;;
;;;; You should have received a copy of the GNU General Public License
;;;; along with this program. If not, see <http://www.gnu.org/licenses/>.
(define-module (gnunet-identity)
#:use-module (guix monads)
#:use-module (gnu gnunet monad)
#:use-module (gnu gnunet configuration)
#:use-module (gnu gnunet identity)
#:use-module (ice-9 match)
#:export (main))
(define (main args)
(define config-file "~/.gnunet/gnunet.conf")
(define config (load-configuration config-file))
(run-with-scheduler config
(mlet* %task-monad ((id (identity-service config)))
(match id
((ego name)
;; Only print the public key of egos that have an associated
;; nickname.
(if name
(begin
(format #t "~a - ~a~%"
name
(ecdsa-public-key->string (ego-public-key ego)))
(return id))
(skip)))))))
;; Local Variables:
;; mode: scheme
;; End:

128
gnu/gnunet/monad.scm Normal file
View File

@ -0,0 +1,128 @@
;;;; Copyright © 2015 Ludovic Courtès <ludo@gnu.org>
;;;;
;;;; This program is free software: you can redistribute it and/or modify
;;;; it under the terms of the GNU General Public License as published by
;;;; the Free Software Foundation, either version 3 of the License, or
;;;; (at your option) any later version.
;;;;
;;;; This program is distributed in the hope that it will be useful,
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;;;; GNU General Public License for more details.
;;;;
;;;; You should have received a copy of the GNU General Public License
;;;; along with this program. If not, see <http://www.gnu.org/licenses/>.
(define-module (gnu gnunet monad)
#:use-module (guix monads)
#:use-module (gnu gnunet scheduler)
#:use-module (gnu gnunet identity)
#:use-module (gnu gnunet fs)
#:use-module (ice-9 match)
#:export (%task-monad
async
delayed
skip
run-with-scheduler
identity-service
file-sharing-service))
;;; Commentary:
;;;
;;; This module provides the "task monad," a monad that abstracts over GNUnet
;;; tasks and callbacks. The goal is to "invert inversion of control" (IoC)
;;; so as to obtain more readable programs. This is essentially
;;; continuation-passing style (CPS) in disguise. Some monadic procedures
;;; such as 'identity-service' may return zero or several times because they
;;; correspond to callbacks.
;;;
;;; Code:
(define-inlinable (task-return value)
(lambda (cont)
(cont value)))
(define-inlinable (task-bind mvalue proc)
(lambda (cont)
(mvalue (lambda (value)
((proc value) cont)))))
(define-monad %task-monad
(bind task-bind)
(return task-return))
;; ((with-monad %task-monad
;; (>>= (return 42)
;; (lift1 1+ %task-monad)
;; (lift1 1+ %task-monad)
;; (lambda (x)
;; (return (* 2 x)))))
;; pk)
(define (run-with-scheduler config mvalue)
"Run MVALUE, a monadic value in %TASK-MONAD, using CONFIG. In practice this
starts the GNUnet scheduler and runs the given tasks."
(call-with-scheduler config
(lambda (x)
(mvalue identity))))
(define-inlinable (task thunk)
"Return the result of THUNK as a monadic value. THUNK will be invoked from
within a GNUnet task."
(lambda (cont)
(add-task! (lambda (_)
(cont (thunk))))))
(define-syntax-rule (async exp)
"Return the result of EXP as evaluated in an asynchronous task."
(task (lambda () exp)))
(define (delayed-task delay thunk)
(lambda (cont)
(add-task! (lambda (_)
(cont (thunk)))
#:delay delay)))
(define-syntax-rule (delayed usec exp)
"Return the result of EXP after waiting for USEC microseconds."
(delayed-task usec (lambda () exp)))
(define* (skip #:optional value)
"Skip the continuation and return VALUE."
(lambda (cont)
value))
;;;
;;; Monadic wrappers.
;;;
(define* (identity-service config)
"Return, zero or more times, an ego/name or ego/#f tuple corresponding to
CONFIG."
(lambda (cont)
(define service
(open-identity-service config
(lambda (ego name)
(if (not ego)
(add-task! (lambda (_)
(close-identity-service service)))
(cont (list ego name))))))
service))
(define* (file-sharing-service config name)
"Return, zero or more times, a handle/info/status tuple from the publication
service."
(lambda (cont)
(define service
(open-filesharing-service config name
(lambda (info status)
(match status
((#:publish #:stopped)
(close-filesharing-service! service))
(_
(cont (list service info status)))))))
service))
;;; monad.scm ends here