[英]Pattern matching on basic types
這是我想要的:
f n = case n of
String -> "string"
_ -> "other"
或者其他的東西。 如果要用字符串調用,我希望f
映射到原義的“字符串”,否則應映射為“其他”。 這不能像我正在做的那么難。
如果您來自JS和Python,那是可以理解的,您認為這應該可行–畢竟,在這些語言中,類型本質上是值的特定屬性。 但這根本不是Haskell類型系統如何工作的! 實際上,類型和值屬於完全獨立的“ Universe”:類型僅在編譯時存在,值僅在運行時存在。 確實每個值都屬於一個類型,但是此信息在編譯時已被完全解析。 在運行時,通常不必分派類型,因為編譯器已經提前進行了分配,並且永遠不可能傳入有效值以外的其他類型的值。因此,這總是多余的。 實際上,在運行程序之前, 已刪除類型信息 。
因此,從直接的意義上說,您要實現的目標確實是不可能的。 或者,憤世嫉俗地說,這很簡單 :
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
與笨拙的eqTypeRep
構造相比,寫f
更優雅的方式是
f :: Dynamic -> String
f s = case fromDynamic s :: Maybe String of
Just _ -> "string"
_ -> "other"
通常,在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"
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.