That mostly sounds ok, but you are right about constraints being functions not a typeclass. In haskell the job of an interface is split in two. Typeclasses handle the this function can take any type that implements this interface part of the equation. An example of this is the Show typeclass. By implementing the Show type class your data type supports the show (to string) function. This means that print will now print instances of your type.
The part of the interface concept where you implement an interface so that you can have multiple implementations of the same function is handled through higher order functions rather than identically named functions attached to different types. As an example of this doFunc opp a b = opp a b
it will have the type (a -> b -> c) -> a -> b -> c. Then this function can take any two operand function and apply it like doFunc (+) 1 2
or doFunc (*) 1 2
.
The main thing I would suggest is try working bottom up. I found it really helped with the build small functions and compose them philosophy of FP programming.