With Swift like that:
protocol EmptyProtocol { }
func printValue<T>(_ value: T) {
print("value: \(value), type: \(type(of: value))")
}
struct MyStruct: EmptyProtocol {
let name: String
}
class MyClass: EmptyProtocol {
let id: Int
init(id: Int) { self.id = id }
}
let items: [EmptyProtocol] = [
MyStruct(name: "Swift"),
MyClass(id: 42)
]
printValue(MyStruct(name: "Swift"))
printValue(MyClass(id: 42))
for item in items {
printValue(item)
}
And the result is:
value: MyStruct(name: "Swift"), type: MyStruct
value: output.MyClass, type: MyClass
value: MyStruct(name: "Swift"), type: EmptyProtocol
value: output.MyClass, type: EmptyProtocol
Which means we loose type information for EmptyProtocol
But with Haskell,
import Data.Typeable
import System.IO
import GHC.IO.Encoding (setLocaleEncoding)
-- 1. Define an empty typeclass
class EmptyProtocol a
-- 2. Define some types and implement the typeclass
data MyStruct = MyStruct String deriving (Show, Typeable)
data MyClass = MyClass Int deriving (Show, Typeable)
instance EmptyProtocol MyStruct
instance EmptyProtocol MyClass
-- 3. Generic function: print value and type
printValue :: (Show a, Typeable a) => a -> IO ()
printValue x = putStrLn $ "Value: " ++ show x ++ ", Type: " ++ show (typeOf x)
-- 4. Existential wrapper for heterogeneous list
data AnyValue = forall a. (Show a, Typeable a) => AnyValue a
castToAny :: (Show a, Typeable a) => a -> AnyValue
castToAny = AnyValue
printAny :: AnyValue -> IO ()
printAny (AnyValue x) = printValue x
-- 5. Main function
main :: IO ()
main = do
let items = [castToAny (MyStruct "Haskell"), castToAny (MyClass 42)]
mapM_ printAny items
We can get right type information
Value: MyStruct "Haskell", Type: MyStruct
Value: MyClass 42, Type: MyClass
It’s such behavior expected?