代码之家  ›  专栏  ›  技术社区  ›  bbarker

在Haskell中有没有直接引用typeclass实例的方法?

  •  0
  • bbarker  · 技术社区  · 7 年前

    这样做的好处可能是将有关类型的某些元数据存储在规范位置。有时,在对类型使用某些实例方法之前,获取该类型的值是不方便的;例如,如果我有:

    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 . 为了使它在某些上下文中有用,可能还需要遍历所有(在范围内?)实例,或在其他上下文中,能够具体实现给定类型的实例。

    我想问题是实例和类型类不是Haskell中的一级实体?

    0 回复  |  直到 7 年前
        1
  •  8
  •   Fyodor Soikin    7 年前

    “老派”的做法是提供一个“伪”参数,其目的只是帮助编译器找到合适的实例。在这个世界上,你的班级看起来像:

    data Dummy a = Dummy
    
    class Foo a where
        foo :: Dummy a -> String
    
    -- usage:
    boolFoo = foo (Dummy :: Dummy Bool)
    

    事实上,这种把戏无处不在 Dummy 类型被半标准化为 Data.Proxy .


    但在现代温室气体控制中,有一种更好的方法: TypeApplications .

    启用此扩展后,可以直接在调用类方法时指定类型:

    class Foo a where
        foo :: String
    
    boolFoo = foo @Bool
    

    (这不仅适用于类方法;它也适用于任何泛型函数,但要注意类型参数的顺序!)

    您可能还需要启用 AllowAmbiguousTypes 为了声明这样的类。虽然我不确定我是否记得这件事,而且我手头也没有电脑可以检查。

        2
  •  5
  •   luqui    7 年前

    旧的方法(我仍然喜欢)是使用 代理 .

    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
    

    这看起来更好,但在实践中使用它往往更恼人的原因,我不能完全把我的手指。

    这回答了问题吗?

    推荐文章