检查一个类型是否是 Haskell 中 Show 的一个实例? [英] Check whether a type is an instance of Show in Haskell?

查看:27
本文介绍了检查一个类型是否是 Haskell 中 Show 的一个实例?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我在 Haskell 中有一个用于存储值的简单数据类型:

Suppose I have a simple data type in Haskell for storing a value:

data V a = V a

我想让 V 成为 Show 的实例,而不管 a 的类型.如果 a 是 Show 的实例,则 show (V a) 应返回 show a 否则应返回错误消息.或者在伪 Haskell 中:

I want to make V an instance of Show, regardless of a's type. If a is an instance of Show, then show (V a) should return show a otherwise an error message should be returned. Or in Pseudo-Haskell:

instance Show (V a) where
    show (V a) = if a instanceof Show
                   then show a
                   else "Some Error."

如何在 Haskell 中实现这种行为?

How could this behaviour be implemented in Haskell?

推荐答案

正如我在评论中所说,分配在内存中的运行时对象在 Haskell 程序中没有类型标记.因此,没有像 Java 中那样通用的 instanceof 操作.

As I said in a comment, the runtime objects allocated in memory don't have type tags in a Haskell program. There is therefore no universal instanceof operation like in, say, Java.

考虑以下内容的含义也很重要.在 Haskell 中,首先近似(即忽略初学者不应过早处理的一些花哨的东西),所有运行时函数调用都是单态.即,编译器直接或间接知道可执行程序中每个函数调用的单态(非泛型)类型.即使您的 V 类型的 show 函数具有通用类型:

It's also important to consider the implications of the following. In Haskell, to a first approximation (i.e., ignoring some fancy stuff that beginners shouldn't tackle too soon), all runtime function calls are monomorphic. I.e., the compiler knows, directly or indirectly, the monomorphic (non-generic) type of every function call in an executable program. Even though your V type's show function has a generic type:

-- Specialized to `V a`
show :: V a -> String  -- generic; has variable `a`

...您实际上无法编写在运行时调用该函数的程序,而不直接或间接地告诉编译器在每次调用中a 的确切类型.例如:

...you can't actually write a program that calls the function at runtime without, directly or indirectly, telling the compiler exactly what type a will be in every single call. So for example:

-- Here you tell it directly that `a := Int`
example1 = show (V (1 :: Int)) 

-- Here you're not saying which type `a` is, but this just "puts off" 
-- the decision—for `example2` to be called, *something* in the call
-- graph will have to pick a monomorphic type for `a`.
example2 :: a -> String
example2 x = show (V x) ++ example1

从这个角度来看,希望您能发现问题所在:

Seen in this light, hopefully you can spot the problem with what you're asking:

instance Show (V a) where
    show (V a) = if a instanceof Show
                   then show a
                   else "Some Error."

基本上,由于 a 参数的类型在编译时对于任何对 show 函数的实际调用都是已知的,因此没有必要在运行时——你可以在编译时测试它!一旦你掌握了这一点,你就会想到 Will Sewell 的建议:

Basically, since the type for the a parameter will be known at compilation time for any actual call to your show function, there's no point to testing for this type at runtime—you can test for it at compilation time! Once you grasp this, you're led to Will Sewell's suggestion:

-- No call to `show (V x)` will compile unless `x` is of a `Show` type.
instance Show a => Show (V a) where ...

<小时>

一个更具建设性的答案可能是这样的:您的 V 类型需要是多个案例的标记联合.这确实需要使用 GADTs 扩展:


A more constructive answer perhaps might be this: your V type needs to be a tagged union of multiple cases. This does require using the GADTs extension:

{-# LANGUAGE GADTs #-}

-- This definition requires `GADTs`.  It has two constructors:
data V a where
  -- The `Showable` constructor can only be used with `Show` types.
  Showable   :: Show a => a -> V a
  -- The `Unshowable` constructor can be used with any type.
  Unshowable :: a -> V a

instance Show (V a) where
  show (Showable a) = show a
  show (Unshowable a) = "Some Error."

但这不是对类型是否为 Show 实例的运行时检查——您的代码负责在编译时知道 Showable 构造函数的位置用过.

But this isn't a runtime check of whether a type is a Show instance—your code is responsible for knowing at compilation time where the Showable constructor is to be used.

这篇关于检查一个类型是否是 Haskell 中 Show 的一个实例?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆