如何输入演员表

时间:2009-12-12 18:55:24

标签: haskell casting

C#:

static int F(object x)
{
 return x is string ? 1 : 2;
}

Haskell的吗 在我看来,棘手的一点是Haskell没有根类型对象

编辑:我不关心转换为字符串。我想知道如何进行类型转换(例如,查看对象客户还是订单

8 个答案:

答案 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类型。

在什么情况下您遇到CustomerOrder的对象?该类型的值简直是荒谬的。请再次澄清。

关于你的记录器示例: 你需要一个类型类:

class Loggable a where
    writeToLog :: a -> IO ()

答案 1 :(得分:20)

Dario是正确的,通常在Haskell中你想要创建一个类型类来调度某些类型。话虽如此,一种在Haskell中强制转换的类型安全方式。这是Scrap your boilerplate通用编程库的一部分,它允许您在SYB填充空白时编写复杂嵌套数据类型操作的“有趣”部分。脑部融化得很棒。以下是ppthtml中的演示文稿。

这是演员的样子:

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功能的语言中有意义。您的问题可以通过多种方式得到解答:

  • Haskell没有子类型,所以is / instanceof在Haskell中毫无意义;只有明确的转换。所有类型都没有object类型。
  • Haskell的类型类提供ad-hoc多态性,并帮助重载多个转换的单个名称。例如(正如其他人指出的那样)show是将任何类型转换为String的重载名称。类型类也可用于使某些转换(似乎)隐式。
  • 使用类型类,通用Scrap Your Boilerplate库的作者创建了一个安全转换函数(也由其他人指出)。

答案 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,因此不需要转换。