[英]Is there a way to refer directly to typeclass instances in Haskell?
这样做的好处是可以在规范位置存储关于类型的某些元数据。 有时,在使用某些实例方法之前获取类型的值是不方便的; 例如,如果我有:
class Foo a where
foo :: String
foo = "Foo"
这实际上不是有效的Haskell。 相反,似乎我必须有类似的东西:
class Foo a where
foo :: a -> String
foo = const "Foo"
现在foo
实际上会有类型Foo a => a -> String
,但我真的希望能够做类似于Instance Foo -> String
的foo
。 为了在某些上下文中有用,可能还需要迭代所有(范围内?)实例,或者在其他上下文中,以便能够具体实现给定类型的实例。
我想问题是实例和类型类不是Haskell中的第一类实体?
“老派”这样做的方式是提供一个“虚拟”参数,其目的只是帮助编译器找到合适的实例。 在这个世界上,你的课程看起来像:
data Dummy a = Dummy
class Foo a where
foo :: Dummy a -> String
-- usage:
boolFoo = foo (Dummy :: Dummy Bool)
事实上,这个技巧无处不在, Dummy
类型被半标准化为Data.Proxy
。
但在现代GHC中有一种更好的方法: TypeApplications
。
启用此扩展后,您可以在调用类方法时直接指定类型:
class Foo a where
foo :: String
boolFoo = foo @Bool
(这不仅适用于类方法;它适用于任何泛型函数,但要注意类型参数的顺序!)
您可能还需要启用AllowAmbiguousTypes
才能声明此类。 虽然我不确定我是否正确记得这个,但我没有一台电脑方便检查。
旧的方式(我更喜欢)是使用代理 。
import Data.Proxy
class Foo a where
foo :: Proxy a -> String
instance Foo FancyPants where
foo _ = "a fancypants instance"
fooString :: String
fooString = foo (Proxy :: Proxy FancyPants)
所以我们实际上并不需要FancyPants
类型的值来使用foo
,我们需要的只是Proxy FancyPants
的值 - 但是你可以创建任何你想要的类型的代理。 这也可以在多态上下文中完成; 通常它需要使用ScopedTypeVariables
扩展。
新的方法是使用TypeApplications
和AllowAmbiguousTypes
扩展:
{-# LANGUAGE TypeApplications, AllowAmbiguousTypes #-}
class Foo a where
foo :: String
instance Foo FancyPants where
foo = "a fancypants instance"
fooString :: String
fooString = foo @FancyPants
这看起来更好,但在实践中使用它往往更加恼人,因为我无法完全按手指。
这回答了这个问题吗?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.