"An existential type is basically a type meaning "any type that implements the given type-class/trait/concept", so you can use to create an array of different types that all satisfy the same contract."
I can't speak for Rust, but when I was first learning Haskell I was bitten by believing it worked that way, but it doesn't:
Prelude> :t sum
sum :: (Num a, Foldable t) => t a -> a
Prelude> sum [1::Int, 2::Int]
3
Prelude> sum [1::Float, 2::Float]
3.0
Prelude> sum [1::Float, 2::Int]
<interactive>:25:16: error:
• Couldn't match expected type ‘Float’ with actual type ‘Int’
• In the expression: 2 :: Int
In the first argument of ‘sum’, namely ‘[1 :: Float, 2 :: Int]’
In the expression: sum [1 :: Float, 2 :: Int]
You can kinda make it work by wrapping it behind yet another type that basically boxes the different underlying types, but that causes its own problems (including, for instance, the fact that no amount of boxing will make this example work; sum is also demonstrating why Haskell won't do this). Basically in Haskell, either do it a different way (and there's usually a different way that will make it work better), or go to full on heterogeneous lists that don't even need the values to be the same type like HList, but unless I've missed an implication of one of the more recent type extensions, you can't have a
simple container like this that has heterogeneous types based on their interface. (I know you can make complex ones, because I have myself, but not the way I'm fairly sure you meant.)