Reputation: 3764
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
Upvotes: 3
Views: 313
Reputation: 1220
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")))))
Upvotes: 2