haskell - Haskell 中的多态类型族实例

标签 haskell polymorphism type-families

我正在尝试编写代码来模拟随机变量,并且我希望尽可能保持多态性。这可能涉及类型族的使用,这对我来说是全新的。

这是我的代码的简化版本:

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}


data TrivialDist a = Trivial a

getVal :: TrivialDist a -> a
getVal (Trivial x) = x

class JointDist d a where
    toTrivialDist :: d a -> TrivialDist [a]

data TrivialJointDist a = TrivialJoint [a]

instance JointDist TrivialJointDist a where
    toTrivialDist :: TrivialJointDist a -> TrivialDist [a]
    toTrivialDist (TrivialJoint xs) = Trivial xs

class Simulable s a where
    type Samp s a :: *
    -- generates infinite stream of random samples from a distribution
    samples :: s a -> IO [Samp s a]
    -- generates a single random sample from a distribution
    sample :: s a -> IO (Samp s a)
    sample = fmap head . samples

instance Simulable TrivialDist a where
    type Samp TrivialDist a = a
    samples :: TrivialDist a -> IO [a]
    samples (Trivial x) = return $ repeat x

instance (JointDist d a) => Simulable d a where
    type Samp d a = [a]
    samples :: d a -> IO [[a]]
    samples = samples . toTrivialDist

当我将它加载到 ghci 时,我得到这个错误:

test.hs:30:10: error:
    Conflicting family instance declarations:
      Samp TrivialDist a = a -- Defined at test.hs:30:10
      Samp d a = [a] -- Defined at test.hs:40:10
   |
30 |     type Samp TrivialDist a = a
   |          ^^^^^^^^^^^^^^^^^^^^^^
Failed, 0 modules loaded.

这个问题似乎与发现的问题相似 here (解释好像是GHC不能根据约束区分类型),但是没有提出解决方案。

如果我将最后一个实例声明更改为:

instance Simulable TrivialJointDist a where
    type Samp TrivialJointDist a = [a]
    samples :: TrivialJointDist a -> IO [[a]]
    samples = samples . toTrivialDist

但是,我失去了多态性的优势,因为我需要为 JointDist d a 的每个子类型进行单独的实例声明。

非常感谢任何帮助!

最佳答案

经过一番折腾,我想我找到了一个使用等式约束而不是显式类型族的解决方案:

class Simulable s a b where
    -- generates infinite stream of random samples from a distribution
    samples :: s a -> IO [b]
    -- generates a single random sample from a distribution
    sample :: s a -> IO b
    sample = fmap head . samples

instance (b ~ a) => Simulable TrivialDist a b where
    samples :: TrivialDist a -> IO [a]
    samples (Trivial x) = return $ repeat x

instance {-# OVERLAPPABLE #-} (JointDist d a, b ~ [a]) => Simulable d a b where
    samples :: d a -> IO [[a]]
    samples = samples . toTrivialDist

{-# OVERLAPPABLE #-} pragma 指示 GHC 允许 TrivialDist a b 实例与 d a b 实例重叠(否则我们得到一个错误)。

关于haskell - Haskell 中的多态类型族实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54727102/

相关文章:

oop - Scala 类型类的多态性

java - 难以理解多态性

haskell - 为什么 GHC 在使用 Coercible 约束时会自相矛盾?

sockets - 通过Network.Browser进行Socks5连接

haskell - 为多个类型签名重用相同的函数体

haskell - 在 GHCI 中执行 Haskell 表达式

haskell - YesodAuthEmail 无法推断出 m ~ HandlerFor site0

haskell - 如何在 Haskell 中创建 "kind class",或使用类型族在类型级别创建临时多态性

c# - 在实现中用派生类覆盖接口(interface)方法返回类型

haskell - 将功能依赖类转换为类型族实例