这就是我想要的:
f n = case n of
String -> "string"
_ -> "other"
或其他。我希望f
映射到文字“字符串”(如果使用字符串调用),否则要映射“其他”。这不像我做的那么难。
答案 0 :(得分:5)
如果您来自JS和Python,这是可以理解的,那么您认为这应该是可能的-毕竟,在这些语言中,类型本质上是值的特定属性。但这根本不是Haskell类型系统如何工作的!实际上,类型和值属于完全独立的“ Universe”:类型仅在编译时存在,值仅在运行时存在。确实每个值都属于一个类型,但是此信息在编译时已被完全解析。在运行时,通常不必分派类型,因为编译器已经提前完成了,并且永远不可能输入除有效值之外的其他类型的值。 >曾经被传入。因此这将总是多余的。实际上the type information is removed在程序运行之前。
因此,从直接的意义上说,您要实现的目标确实是不可能的。或者,愤世嫉俗地说,这很简单:
f :: String -> String
f _ = "string"
通常,如果您发现自己想对类型进行运行时调度,则表明您可能首先应该从变量类型开始:
data StringOrInt = It'sAString String | It'sAnInt Int
f :: StringOrInt -> String
f (It'sAString _) = "string"
f (It'sAnInt _) = "int"
...最好使用更具描述性的,特定于应用程序的名称。
这就是说, 实际上有可能在Haskell中具有“动态类型化”的值,就像在Python中一样。您只需要请求包含类型信息的包装器,否则编译器会在运行时删除这些信息:
{-# LANGUAGE TypeFamilies #-}
import Data.Dynamic
import Type.Reflection
f :: Dynamic -> String
f (Dynamic t _)
= case eqTypeRep t (typeOf "string") of
Just HRefl -> "string"
_ -> "other"
用法示例:
main = do
putStrLn . f $ toDyn "bla"
putStrLn . f $ toDyn True
putStrLn . f $ toDyn 'y'
屈服
string other other
比笨拙的f
结构更优雅的写eqTypeRep
的方式
f :: Dynamic -> String
f s = case fromDynamic s :: Maybe String of
Just _ -> "string"
_ -> "other"
答案 1 :(得分:1)
通常,在Haskell中像这样的临时多态性和类型自省不被接受。仍然有可能,但是有点脆弱:
{-# LANGUAGE FlexibleInstances #-}
class F a where
f :: a -> String
instance F String where
f n = "string"
instance {-# OVERLAPPABLE #-} F other where
f n = "other"
或者,您可以使用不太脆弱的Typeable
,但需要从调用者处获得实例:
import Data.Typeable
f :: Typeable a => a -> String
f n = if typeOf n == typeOf "" then "string" else "other"