Автоматическая вставка ожидает, когда функция asyncio в Hy-Lang - PullRequest
0 голосов
/ 16 января 2020

Следующий макрос do/a может автоматически вставлять await при использовании функции asyncio. Далее также показано использование.

(import asyncio)
(import time)

(defmacro do/a [&rest code] 
  `(do ~@(lfor p code
                (if
                  (= (cut (str (first p)) -2) "/a")
                  `(await ~p)
                  p))))

(defmacro progn/a [&rest code]
  `(.run_until_complete (.get-event-loop asyncio )
     ((fn/a []
        (do/a ~@code)
        ))
     ))

(defn/a sleep_test/a [t]  
  (await (asyncio.sleep t))
  (print t)
  t)

(defn sleep_test [t]  
  (time.sleep t)
  (print t)
  t)

(progn/a
  (print 3)
  (await (sleep_test/a 3))
  (sleep_test/a 2) ;;can omit await
  (sleep_test 1) ;;auto swich by fn name 
  (+ 20 30)
  )

Этот макрос обнаруживает асинхронную c функцию по имени функции "/ a". Лучше использовать asyncio.iscoroutinefunction для обнаружения асинхронных c функций. Но это не работает. Пожалуйста, посмотрите следующий макрос и выполненный результат.

(defmacro isasynctestmac [f]
  (if (asyncio.iscoroutinefunction f)
      `["async"  ~(asyncio.iscoroutinefunction f) (asyncio.iscoroutinefunction ~f) (type ~f)] 
      `["not async" ~(asyncio.iscoroutinefunction f) (asyncio.iscoroutinefunction ~f) (type ~f)] 
          ))

(isasynctestmac sleep_test/a)

==> ['not async', False, True, <class 'function'>]

Вы увидите, что асиновая c функция рассматривается как символ в макросе hy-lang. Применение eval не может избежать этой проблемы.

Как решить эту проблему?

Ответы [ 2 ]

1 голос
/ 16 января 2020

Макросы выполняются во время компиляции, а то, содержит ли переменная сопрограмму, известно только во время выполнения, поэтому iscoroutinefunction необходимо вызывать во время выполнения. (asyncio.iscoroutinefunction f) в вашем макросе isasynctestmac просто проверяет символ, который используется в качестве имени переменной, а не значение переменной. Вот как вы можете написать do/a с iscoroutinefunction, а вот остальную часть кода, например, с удалением лишних скобок в sleep_test. (В будущем убедитесь, что части вашего кода, которые должны работать, уже работают, прежде чем отправлять их в Stack Overflow.)

(import asyncio time) 

(defmacro do/a [&rest code] 
  `(do ~@(lfor p code
    (if (and (instance? HyExpression p) p (!= (first p) (HySymbol "await")))
      `(if (asyncio.iscoroutinefunction ~(first p))
        (await ~p)
        ~p)
      p))))

(defmacro progn/a [&rest code]
  `(.run_until_complete (.get-event-loop asyncio)
    ((fn/a []
      (do/a ~@code)))))

(defn/a sleep_test/a [t]  
  (await (asyncio.sleep t))
  (print t)
  t)

(defn sleep_test [t]  
  (time.sleep t)
  (print t)
  t)

(print (progn/a
  (print 3)
  (await (sleep_test/a 3))
  (sleep_test/a 2)
  (sleep_test 1)
  (+ 20 30)))
0 голосов
/ 04 февраля 2020

У подхода @Kodiologist show есть следующая проблема. Следующий код python работает.

import asyncio
import time
async def sleep_testa(t, hintfn):
    await asyncio.sleep(t) if asyncio.iscoroutinefunction(hintfn) else time.sleep(t)

Но после удаления async до def программа останавливается с ошибкой SyntaxError: invalid syntax

import asyncio
import time
def sleep_testa(t, hintfn):
    await asyncio.sleep(t) if asyncio.iscoroutinefunction(hintfn) else time.sleep(t)
==> SyntaxError: invalid syntax

Кажется, что невозможно динамически переключение асинхронного c и не асинхронного c кода. Мы должны поменять асин c и не асин c код перед расширением макроса.

...