C#:
static int F(object x)
{
return x is string ? 1 : 2;
}
Haskell的吗 在我看来,棘手的一点是Haskell没有根类型对象。
编辑:我不关心转换为字符串。我想知道如何进行类型转换(例如,查看对象是客户还是订单。
答案 0 :(得分:37)
在Haskell中,允许转换为字符串的所有类型都实例化提供的Show
类型类
show :: Show a => a -> String
所以你的整个代码只不过是
f x = show x
或
f = show
使用相同的泛型类型f :: Show a => a -> String
(Forall类型a
可以与字符串对话,获取此类型的值并返回一个字符串)。
请注意,您不必像在C#中那样进行显式的运行时类型检查;通用模板在编译时解析。你不需要多态的根类型 - 像C#中的强制转换实际上有点复杂并且违背了语言的概念。它不是允许在类型之间进行任意强制转换,而是为某些有意义的转换定义了类型类。
请注意,在编译时检查兼容性:
-- Working
f 1
f "Hallo"
f (1, 2)
f [1, 2, 3]
-- Not working
f (\x -> x + 1)
回复您编辑过的问题:
正如我之前所说,Haskell中不允许任意转换(没有非常不安全的代码)。由于Haskell不是面向对象的,因此没有需要任何强制转换的继承关系。根本没有需要运行时检查/转换的无意义的object
值。要表达替代方案,您必须定义联合类型,类型类或使用Either
类型。
在什么情况下您遇到Customer
或Order
的对象?该类型的值简直是荒谬的。请再次澄清。
关于你的记录器示例: 你需要一个类型类:
class Loggable a where
writeToLog :: a -> IO ()
答案 1 :(得分:20)
Dario是正确的,通常在Haskell中你想要创建一个类型类来调度某些类型。话虽如此,是一种在Haskell中强制转换的类型安全方式。这是Scrap your boilerplate通用编程库的一部分,它允许您在SYB填充空白时编写复杂嵌套数据类型操作的“有趣”部分。脑部融化得很棒。以下是ppt或html中的演示文稿。
这是演员的样子:
cast :: (Typeable a, Typeable b) => a -> Maybe b
ghci> (cast 'a') :: Maybe Char
Just 'a'
ghci> (cast 'a') :: Maybe Bool
Nothing
ghci> (cast True) :: Maybe Bool
Just True
答案 2 :(得分:9)
投射和is
/ instanceof
在具有subtyping功能的语言中有意义。您的问题可以通过多种方式得到解答:
is
/ instanceof
在Haskell中毫无意义;只有明确的转换。所有类型都没有object
类型。show
是将任何类型转换为String的重载名称。类型类也可用于使某些转换(似乎)隐式。答案 3 :(得分:4)
最直接的方法是使用Data.Typeable,正如Dario观察到的那样,涵盖了所有标准类型,但您需要传递“Deriving Typeable
”,或以其他方式实施typeOf
要涵盖的自己的类型定义。这不是标准的Haskell 98,但它是自6.2.2以来的ghc。
您的代码可以实现:
stringtyperep :: TypeRep stringtyperep = typeOf "somestring" F :: (Typeable 'a) =>'a -> Integer F x | (typeOf x == stringtyperep) = 1 F x = 2
通常,使用泛型编程可以更好地完成OO样式的反射,但这不是一个很好的例子。
此外,类型Typeable
中的所有类型都可以“强制转换”为Data.Dynamic。
答案 4 :(得分:3)
如果您想拥有可以是Customers或Orders的对象,那么您将引入一个新的数据类型“Customer | Order”,以便每个对象都带有一个类型标记,说明它是什么。
我不知道Haskell语法,但在F#中它将是
type CustOrOrd =
| Cust of Customer
| Ord of Order
let F (x:CustOrOrd) : int =
match x with
| Cust c -> 1
| Ord o -> 2
let thing1 = Cust someCustomer
let thing2 = Ord someOrder
// can call F on thing1 or thing2
更一般地说,在Haskell中,如果你想做一些固定的OO类型层次结构(对于一组固定的高度相关的类型,在某些情况下能够将它们视为相同的类型),你可以使用一个联合如上所述。另一方面,对于跨各种不相关类型(如ToString / Show)的常见操作,您可以使用Haskell类型类。
答案 5 :(得分:3)
这是我以前尝试过的,我认为你不能这样做。
Introduction to Haskell Pure Functions
Haskell采取了非常不同的方式 做法。它从执行类型开始 使用类型检查器进行分析 在编译时理解你的程序 时间。 严格的类型检查器 禁止铸造而不是 允许忽略类型错误。 因为在编译时检查类型 时间,并没有逃脱 类型检查器,Haskell经常 描述为静态类型和 强烈打字。
答案 6 :(得分:3)
Object
如果您的用例非常简单,最好自己定义对象类型,因此:
data Type = String | Integer | List | Bool
deriving (Eq, Show)
class Object a where
typeOf :: a -> Type
instance Object String where typeOf _ = String
instance Object Integer where typeOf _ = Integer
instance Object [a] where typeOf _ = List
instance Object Bool where typeOf _ = Bool
f :: (Object a, Num b) => a -> b
f x = if typeOf x == String then 1 else 2
显然,您必须为您可能希望在函数中使用instance
的每个类型编写typeOf
声明。当你尝试为元组定义instance
时,这可能会变得棘手,因为在Haskell中,如果两个元组没有相同数量的元素,则它们具有不同的类型,因此您可能必须编写无限数量的{ {1}}声明,就像这样:
instance
data Type = String | Integer | List | Bool | Tuple
deriving (Eq, Show)
instance Object () where typeOf _ = Tuple
instance Object (a) where typeOf _ = Tuple
instance Object (a,b) where typeOf _ = Tuple
instance Object (a,b,c) where typeOf _ = Tuple
instance Object (a,b,c,d) where typeOf _ = Tuple
instance Object (a,b,c,d,e) where typeOf _ = Tuple
instance Object (a,b,c,d,e,f) where typeOf _ = Tuple
instance Object (a,b,c,d,e,f,g) where typeOf _ = Tuple
如果您的使用情况变得更复杂,您可以尝试Data.Typeable
:
Data.Typeable
如果您愿意,可以将import Data.Typeable
f :: (Typeable a, Num b) => a -> b
f x = if typeOf x == typeOf (undefined::String) then 1 else 2
替换为(undefined::String)
;无论哪种阅读都比较容易。
答案 7 :(得分:2)
在C#中,不进行演员表可能更有效率:
return x == null ? null : x.ToString();
在Haskell中有“show”类型类,实现类型类的任何东西都可以在其上调用show,因此不需要转换。