I don't know about OCaml, but Haskell has typeclasses (which look like "polymorphic interfaces"?) so you can define functions generically and put a typeclass constraint to make them work on a certain class of types. E.g. your avg function would be of type:
avg :: Num a => a -> a -> a
Where your "a" is a number (that is, a type that implements the Num typeclass)
This would work out of the box on floats, ints, etc
Re:A Year in Clojure
by StreamBright on Sunday October 07, 2018 @01:03PM
(#18161552)
The signature is not really helpful. Can you show me how do you implement the actual function?
If you have operators that are typed like + and +. how can you make this work with Num?
Also the + operator is typed with Num; from a Haskell repl:
λ> :t (+)
(+) :: Num a => a -> a -> a
In case of average we need /: λ> :t (/)
(/) :: Fractional a => a -> a -> a
So our type is going to be constrained by Fractional instead of Num). So an implementation could be (from here [1]): import Data.List
average :: (Real a, Fractional b) => [a] -> b
average xs = realToFrac (sum xs) / genericLength xs
[1]: https://stackoverflow.com/questions/2376981
utop # let avg a b = (a +. b) /. 2.0;;
val avg : float -> float -> float = <fun>
utop # avg 2 4;;
Error: This expression has type int but an expression was expected of type float
utop # avg 2.0 4.0;;
- : float = 3.
user=> (defn avg [a b] (/ (+ a b) 2))
#'user/avg
user=> (avg 2 4) 3
user=> (avg 2.0 4.0) 3.0
I think it is a matter of taste which one you prefer. With property based testing and specs you can go very far in term of pre-runtime checks and there was some data about the number of bugs per line published by Github where it turned out that Clojure did not do too bad in comparison to statically typed languages.