我可以在类型名称上模式匹配吗?

时间:2016-04-28 16:07:00

标签: haskell

是否可以在类型名称本身而不是在某个类型的构造函数上进行模式匹配?

这是一个人为的例子,代码没有编译,我希望能解释我之后的事情:

what :: a -> String
what (x :: String) = "It's a String!"
what (x :: Int) = "It's an Int!"
what x = "Not sure what it is."

4 个答案:

答案 0 :(得分:6)

这是一个使用type-classes的版本:

{-# LANGUAGE TypeSynonymInstances, FlexibleInstances  #-}
module Test where

class What a where
  what :: a -> String

instance What String where
  what _ = "It's a String!"

instance What Int where
  what _ = "It's an Int"

示例:

λ> what "hi"
"It's a String!"
λ> what (1 :: Int)
"It's an Int"

如果您想要 else 案例:

{-# LANGUAGE TypeSynonymInstances, FlexibleInstances, OverlappingInstances  #-}
module Test where

class What a where
  what :: a -> String

instance What String where
  what _ = "It's a String!"

instance What Int where
  what _ = "It's an Int"

instance What a where
  what _ = "not sure"

示例:

λ> what "hi"
"It's a String!"
λ> what (1 :: Int)
"It's an Int"
λ> what True
"not sure"

答案 1 :(得分:5)

警告

请注意,您要求的是一些非惯用的东西。无论你真正想做什么,这可能都不是正确的做法!

解决方案

您的顶级类型签名表示您可以处理任何类型的任何类型,而且不会飞。类型在编译时都会丢失,因此您需要一些东西来告知代码类型是什么,这是做出分支决策的。

你可以在这里使用一些较少使用的课程。一个叫做Typeable,是一个具有运行时表示的类型的类:

class Typeable (a :: k) where
  Data.Typeable.Internal.typeRep# :: GHC.Prim.Proxy# a -> TypeRep

为了在你的情况下使用typeable,你可以将约束添加到你的类型变量中,并使用typeOf来获取类型表示:

{-# LANGUAGE MultiWayIf #-}
import Data.Typeable

what :: Typeable a => a -> String
what x =
    let ty = typeOf x
    in if | ty == intTy -> "It's an Int!"
          | ty == strTy -> "It's a String!"
          | otherwise -> "Something else, namely: " ++ show ty
  where
  strTy = typeOf ""
  intTy = typeOf (0 :: Int)

让步操作:

*Main> what (1::Int)
"It's an Int!"
*Main> what "foo"
"It's a String!"
*Main> what 1.1
"Something else, namely: Double"

答案 2 :(得分:4)

不,那是不可能的。

根据类型执行不同操作的唯一方法是使用对每种类型实现不同的类型类方法。

答案 3 :(得分:3)

在某种程度上,你试图在Haskell中重载一个函数。看一下这篇解释涉及类型类的方法的帖子:Overloading function signatures haskell