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
maxwill never be called with zero arguments.Here's one approach: