基本类型的模式匹配

时间:2019-05-04 20:45:44

标签: haskell

这就是我想要的:

f n = case n of
  String -> "string"
  _ -> "other"

或其他。我希望f映射到文字“字符串”(如果使用字符串调用),否则要映射“其他”。这不像我做的那么难。

2 个答案:

答案 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"