Как аннотировать протоколы и их методы в core.typed Clojure?

Я делаю игру в крестики-нолики и составил протокол для своей стратегии. Игра работает нормально, поэтому я хочу воспользоваться этой возможностью, чтобы отточить свои навыки core.typed. Я аннотировал протокол (как показано ниже), но когда я запускаю (cf method-name) или (cf protocol-name) в ответе, я получаю эту ошибку:

eg:

=> `(cf win)`
clojure.lang.ExceptionInfo: Type Checker: Found 1 error :: {:type-error :top-level-error, :errors (#<ExceptionInfo clojure.lang.ExceptionInfo: Unannotated var tic-tac-toe.protocol/win
Hint: Add the annotation for tic-tac-toe.protocol/win via check-ns or cf {:env {:file "/Users/jessediaz/Documents/workspace/tic-tac-toe/src/tic_tac_toe/protocol.clj", :column 5, :line 47}, :form win, :type-error :clojure.core.typed.errors/tc-error-parent}>)}

Я проверил, чтобы убедиться, что версия протокола на самом деле является core.typed/protocol. Консоль рявкнула на меня, когда я использовал протокол>, говоря, что синтаксис устарел. Я также просмотрел документацию как на странице github, так и на clojure-doc.org. Так я узнал, что есть необязательное ключевое слово :methods, которое я могу использовать для сопоставления методов с типами. Я чувствую, что это могло бы удалить много повторений из моего кода, но я не смог найти никаких примеров его использования. все основные методы стратегии в протоколе имеют побочные эффекты и возвращают nil. Методы проверки либо возвращают nil, либо исходные Strategy методы, которые они проверяют. Я не уверен, что у меня правильный синтаксис, но код отлично оценивается в LightTable, с подписью Fn или без нее, и вики core.typed подразумевает, что это не всегда необходимо.

Я чувствую, что нахожусь на пороге изучения этой удивительной библиотеки и был бы признателен за любой проницательный совет, который мог бы помочь моему пониманию.

файл протокола.clj:

(ns tic-tac-toe.protocol
  (:require [clojure.core.typed :refer :all]))

(ann-protocol Strategy
                win                        (Fn [Strategy -> nil])
                block                      (Fn [Strategy -> nil])
                fork                       (Fn [Strategy -> nil])
                block-fork                 (Fn [Strategy -> nil])
                take-center                (Fn [Strategy -> nil])
                take-opposite-corner       (Fn [Strategy -> nil])
                take-corner                (Fn [Strategy -> nil])
                take-side                  (Fn  [Strategy -> nil])

                can-win?                   (Fn [Strategy -> (U nil (Fn [Strategy -> nil]))])
                can-block?                 (Fn [Strategy -> (U nil (Fn [Strategy -> nil]))])
                can-fork?                  (Fn [Strategy -> (U nil (Fn [Strategy -> nil]))])
                can-block-fork?            (Fn [Strategy -> (U nil (Fn [Strategy -> nil]))])
                can-take-center?           (Fn [Strategy -> (U nil (Fn [Strategy -> nil]))])
                can-take-corner?           (Fn [Strategy -> (U nil (Fn [Strategy -> nil]))])
                can-take-side?             (Fn [Strategy -> (U nil (Fn [Strategy -> nil]))]))
(defprotocol Strategy
  "Strategy methods update the Tic-tac-toe board when they are called"

  ;; strategies
  (win [_] "wins the game by filling an open space to get 3 in a row")
  (block [_] "blocks an opponents win by filling an open space")
  (fork [_] "creates a two way win scenario guaranteeing victory")
  (block-fork [_] "prevents an opponent from forking")
  (take-center [_] "takes center")
  (take-opposite-corner [_] "takes a corner opposite to one the computer already has")
  (take-corner [_] "takes an avaiable corner")
  (take-side [_] "takes an available side")

  ;; tests
  (can-win? [_])
  (can-block? [_])
  (can-fork? [_])
  (can-block-fork? [_])
  (can-take-center? [_])
  (can-take-opposite-corner? [_])
  (can-take-corner? [_])
  (can-take-side? [_]))

person kurofune    schedule 08.12.2014    source источник


Ответы (1)


Я подозреваю, что вам нужно check-ns текущее пространство имен, прежде чем запрашивать его с помощью cf. Оценка введенного кода не запускает проверку типов или сбор аннотаций.

ann-protocol здесь не нужен, clojure.core.typed/defprotocol поддерживает встроенную аннотацию.

Попробуйте что-то вроде:

(defprotocol Strategy
  "Strategy methods update the Tic-tac-toe board when they are called"

  ;; strategies
  (win [_] :- nil "wins the game by filling an open space to get 3 in a row")
  (block [_] :- nil "blocks an opponents win by filling an open space")
  ...)
person Ambrose    schedule 08.12.2014
comment
Спасибо Амвросий! Я попробую. - person kurofune; 08.12.2014
comment
Выводятся ли типы ввода для этих методов? - person kurofune; 08.12.2014
comment
Типы 'self' выводятся и не могут быть переопределены (пока!) непосредственно в defprotocol. Для неполиморфных протоколов «я» — это стратегия, в противном случае это (стратегия a b c), предполагая, что протокол параметризован a, b и c. - person Ambrose; 08.12.2014
comment
Однако все параметры после 1-го не выводятся. - person Ambrose; 08.12.2014
comment
В этом есть смысл. Но что, если я возвращаю либо nil, либо метод Strategy, должен ли я аннотировать его :- (U nil [nil]) или что-то в этом роде? - person kurofune; 08.12.2014
comment
Нм я разобрался. ':- (U nil (Fn [Стратегия -› nil])' Большое спасибо! - person kurofune; 08.12.2014