When creating functions of varying arity, you generally need a function from values to types. In this case, we need a function from List ℕ
(or simply ℕ
- the length of the list) to Set
:
Predicate : ℕ → Set
Predicate zero = Bool
Predicate (suc n) = ℕ → Predicate n
This allows us to create different type for each number:
Predicate 0 = Bool
Predicate 1 = ℕ → Bool
Predicate 2 = ℕ → ℕ → Bool
-- and so on
Now, how do we use Predicate
to express the type of f
? Since we are in dependently typed language, we can freely use value-level functions in types. So length
seems to be a natural fit:
f : (l : List ℕ) → Predicate (length l)
Now, you didn't specify any particular f
, but for the sake of the example, I'm going to implement one. Let's say that we want to check if all the numbers at corresponding positions (i.e. 1st argument to the function with 1st element of the list and so on) are equal.
I picked a rather simple function, so the implementation will be quite straightforward. But note that these kinds of functions use various tricks not unlike those used for implementing variadic functions with type classes (in Haskell).
When given an empty list, we'll simply return true
:
f [] = true
For the nonempty list case, we create a function taking one argument named n
and then compare it to the head of the list (m
). If those numbers are not equal, we'll shortcut the rest of f
and return a function that ignores all other numbers and simply returns false
; if those numbers are equal, we'll simply continue with the rest of the list:
f (m ∷ ms) = λ n → case m ≟ n of λ
{ (yes _) → f ms
; (no _) → always-false
}
And the helper function always-false
:
always-false : ∀ {n} → Predicate n
always-false {zero} = false
always-false {suc _} = λ _ → always-false
And here's how you'd use it:
test : Bool
test = f (1 ∷ 2 ∷ 3 ∷ []) 1 2 4 -- false
As a final remark: those functions are not very useful when you do not have any information about the argument you are applying it to. For example, if you use f
on a list of unknown length (that was given as an argument to another function), you can't even apply the "predicate" to a number. It's quite possible that the list is empty in which case the predicate is Bool
and cannot be applied to anything.