Вопрос

I'm going through project euler again to develop and hone my core.typed skills. However I am having a ton of difficulty understanding the output of the type checker. I'm asking after reading several introductory materials to core.typed as well as some information on the core.typed wiki.

I am using the following code, and please note that the annotation to apply, as well as mapping num over the input in function euler3 has no effect. The error message is still generated. Please ignore the obviously bad factors and prime? functions. I chose naive implementations to allow me to focus on the type annotations.

(ns euler-clj.euler3
"Project euler problem 3.
 Uses a very naive prime tester, would use a sieve or probabilistic
 prime algorithm for a larger problem set.
 What is the largest prime factor of the number 600851475143?"

(:require [clojure.core.typed :refer
          [ann check-ns Int fn> non-nil-return Seq cf]]
          [euler-clj.euler1 :as e1]))

(non-nil-return clojure.lang.Numbers/quotient :all)
(ann ^:no-check clojure.core/apply [[Number Number * -> Number] (Seq Number) -> Number])

(ann factors [Int -> (Seq Int)])
(defn factors
  [n]
  (filter (fn> [m :- Int] (e1/div-by m n)) (range 1 (inc (quot n 2)))))

; Very bad prime function, should be sieve/probabilistic.
; Also identifies 1 as prime incorrectly.
(ann prime? [Int -> Boolean])
(defn prime? [n] (= [1] (factors n)))

(ann euler3 [Int -> Number])
(defn euler3
  [n]
  (apply max (map num (filter prime? (factors n)))))

(ann -main [-> nil])
(defn -main
  []
  (prn (euler3 600851475143)))

This produces the following error:

Type Error (euler-clj.euler3:26:3) Bad arguments to apply: 

Target:         (Fn [java.lang.Number java.lang.Number * -> java.lang.Number])

Arguments:      (clojure.core.typed/Seq java.lang.Number)
in: (clojure.core/apply clojure.core/max (clojure.core/map clojure.core/num (clojure.core/filter euler-clj.euler3/prime?
 (euler-clj.euler3/factors n))))


ExceptionInfo Type Checker: Found 1 error  clojure.core/ex-info (core.clj:4327)
Start collecting euler-clj.euler3
Start collecting euler-clj.euler1
Finished collecting euler-clj.euler1
Finished collecting euler-clj.euler3
Collected 2 namespaces in 62.584894 msecs
Start checking euler-clj.euler1
Checked euler-clj.euler1 in 165.76663 msecs
Start checking euler-clj.euler3
Checked euler-clj.euler3 in 200.997234 msecs
Checked 2 namespaces (approx. 60 lines) in 430.302357 msecs

What type annotations do I need to provide to get apply to accept max and then this seq of numbers?

Thanks

Это было полезно?

Решение

Firstly, you should not provide your own type for apply; it's implemented as a special case in the type checker.

In this case, core.typed needs a bit of convincing that max will never be called with zero arguments.

Here's one approach:

(ann euler3 [Int -> Number])
(defn euler3
  [n]
  (let [[f & r] (map num (filter prime? (factors n)))]
    (if f
      (apply max f r)
      (throw (Exception. "No prime factors")))))
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top