Haskell - 类型和 if 语句
Haskell - types and if statements
有没有什么好的方法可以利用类型信息来选择做不同的事情?
例如,这无效 Haskell,但我不明白为什么不能:
tostring :: (Show b) => b -> String
tostring x = f x where f = if b == String then tail . init . show else show
重要的部分不是得到正确的字符串,而是使用 b
的类型作为在 functionality/functions.
之间切换的方式
我会原样回答问题。 Haskell 在编译期间擦除所有类型信息,主要是出于效率原因。默认情况下,当调用多态函数时,例如f :: a->a
,没有可用的类型信息,f
也没有办法知道 a
到底是什么——在这种情况下,f
只能是恒等函数,失败终止或引发错误。
对于需要类型信息的极少数情况,Typeable
。具有类型 f :: Typeable a => ...
的多态函数被传递给类型 a
的 run-time 描述,允许它对其进行测试。本质上,Typeable a
约束强制 Haskell 将 运行 时间信息保留到 运行 时间。请注意,在调用站点必须知道此类类型信息——要么是因为 f
是用完全已知的类型调用的,要么是因为 f
是用部分已知的类型调用的(比如 f x
x :: Maybe b
) 但在范围内有合适的 Typeable
约束(Typeable b
,在前面的示例中)。
无论如何,这里有一个例子:
{-# LANGUAGE TypeApplications, ScopedTypeVariables, GADTs #-}
import Data.Typeable
tostring :: forall b. (Show b, Typeable b) => b -> String
tostring x = case eqT @b @String of -- if b==String
Just Refl -> x -- then
Nothing -> show x -- else
请注意我们如何能够在“then”分支中 return x
,因为已知它是 String
.
@chi 的回答已经演示了如何使用 Typeable
进行 run-time 类型检查,但我想向我指出,这看起来正是类型类的用途.对于您的示例,唯一的问题是您不喜欢 String
的 Show
实现:在那种情况下,只需创建您自己的类型类!
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
-- The class
class MyShow a where
myShow :: a -> String
-- The instance for String
-- (The `OVERLAPPING` pragma is required, because
-- otherwise GHC won't know which instance to choose for String)
instance {-# OVERLAPPING #-} MyShow [Char] where
myShow = tail . init . show
-- For everything that is not a String, just copy the Show instance
instance Show a => MyShow a where
myShow = show
编辑:正如 leftaroundabout 所指出的,重叠的实例很复杂,可能会导致一些意外行为。查看文档底部的example。
有没有什么好的方法可以利用类型信息来选择做不同的事情?
例如,这无效 Haskell,但我不明白为什么不能:
tostring :: (Show b) => b -> String
tostring x = f x where f = if b == String then tail . init . show else show
重要的部分不是得到正确的字符串,而是使用 b
的类型作为在 functionality/functions.
我会原样回答问题。 Haskell 在编译期间擦除所有类型信息,主要是出于效率原因。默认情况下,当调用多态函数时,例如f :: a->a
,没有可用的类型信息,f
也没有办法知道 a
到底是什么——在这种情况下,f
只能是恒等函数,失败终止或引发错误。
对于需要类型信息的极少数情况,Typeable
。具有类型 f :: Typeable a => ...
的多态函数被传递给类型 a
的 run-time 描述,允许它对其进行测试。本质上,Typeable a
约束强制 Haskell 将 运行 时间信息保留到 运行 时间。请注意,在调用站点必须知道此类类型信息——要么是因为 f
是用完全已知的类型调用的,要么是因为 f
是用部分已知的类型调用的(比如 f x
x :: Maybe b
) 但在范围内有合适的 Typeable
约束(Typeable b
,在前面的示例中)。
无论如何,这里有一个例子:
{-# LANGUAGE TypeApplications, ScopedTypeVariables, GADTs #-}
import Data.Typeable
tostring :: forall b. (Show b, Typeable b) => b -> String
tostring x = case eqT @b @String of -- if b==String
Just Refl -> x -- then
Nothing -> show x -- else
请注意我们如何能够在“then”分支中 return x
,因为已知它是 String
.
@chi 的回答已经演示了如何使用 Typeable
进行 run-time 类型检查,但我想向我指出,这看起来正是类型类的用途.对于您的示例,唯一的问题是您不喜欢 String
的 Show
实现:在那种情况下,只需创建您自己的类型类!
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
-- The class
class MyShow a where
myShow :: a -> String
-- The instance for String
-- (The `OVERLAPPING` pragma is required, because
-- otherwise GHC won't know which instance to choose for String)
instance {-# OVERLAPPING #-} MyShow [Char] where
myShow = tail . init . show
-- For everything that is not a String, just copy the Show instance
instance Show a => MyShow a where
myShow = show
编辑:正如 leftaroundabout 所指出的,重叠的实例很复杂,可能会导致一些意外行为。查看文档底部的example。