haskell 写一个类型同义词的函子示例及其困惑

jutyujz0  于 9个月前  发布在  其他
关注(0)|答案(1)|浏览(72)

我试图实现一个通用的环,并将其应用于Paul Hudak在《The Haskell School of Music》一书中描述的音乐数据结构。当然,这里省略了很多半群/Monoid的恶作剧,但我有以下相关代码:

newtype Duo     a b     = Duo     {duo1     :: a} -- A ring-like structure

data Song a =
       Primitive a
     | Song a :+: Song a             -- Composing Music Sequentially
     | Song a :=: Song a deriving Eq -- Composing Music Concurrently (in parallel)

instance Functor Song where
     fmap f (x :+: y)     = fmap f x :+: fmap f y
     fmap f (x :=: y)     = fmap f x :=: fmap f y
     fmap f (Primitive x) = Primitive $ f x

newtype Concurrent a = Concurrent {fromConcurrent :: Song a} deriving (Show)
newtype Sequential a = Sequential {fromSequential :: Song a} deriving (Show)

type Music a = Duo (Maybe (Concurrent a)) (Maybe (Sequential a))

我正在尝试为音乐编写一个Functor示例,因为Duo没有Functor,我认为这不会是一个问题。
我写了以下实现:

instance Functor Music where
     fmap :: (a -> b) -> Music a -> Music b
     fmap f = Duo . fmap (fmap f . fromConcurrent) . duo1

但我得到以下错误:

• The type synonym ‘Music’ should have 1 argument, but has been given none
• In the instance declaration for ‘Functor Music’
| 167 | instance Functor Music where
|          ^^^^^^^^^^^^^

也许问题只是我本质上只是为Duo的一个子集写了一个函子,也许只有当我把音乐变成一个 * 新类型 * 而不仅仅是一个类型同义词时,这才能起作用。我真的希望避免这种情况,因为这段代码中已经有大量的 Package 器,我真的不想再添加一个。也许你们都能想到一种方法来实现一个有意义的函数,使这一切工作?
有一件事我真的不明白,为什么它让我做一个例子来展示:

instance (Show a) => Show (Music a) where
     show (Duo Nothing)               = "Silence"
     show (Duo (Just (Concurrent x))) = show x
ddarikpa

ddarikpa1#

不幸的是,Haskell中不允许这种类型级别的抽象。但我认为你可能在数据类型设计的某个地方犯了某种概念上的错误。扩展类型,由于Duo只有一个字段,我们将得到:

Music a ~= Duo (Maybe (Concurrent a)) (Maybe (Sequential a))
        ~= Maybe (Concurrent a)
        ~= Maybe (Song a)

这真的是你的本意吗
如果是这样的话,我想我会很想跳过中间人。

data Music a = Silence | Sound (Song a)
instance Functor Music where
    fmap f Silence = Silence
    fmap f (Sound notes) = Sound (fmap f notes)

如果这是预期的行为,但你必须保持中间商,newtype是前进的方向。
如果这不是您希望Music的行为方式,我们可能会给予更多/更好的建议,但我们需要更多地了解您希望Duo的含义。
关于您对Show的编辑/评论:在您Show示例中,您包含了Music的类型参数。Functor示例的问题恰恰在于您没有包含参数。在Show示例中,由于参数可用,编译器可以简单地扩展类型别名,因此行

instance Show a => Show (Music a)

在编译器关心的所有方面都与行相同

instance Show a => Show (Duo (Maybe (Concurrent a)) (Maybe (Sequential a)))

但是,在Functor示例中,编译器无法展开类型别名,因为您没有提供类型参数。您可以想象在Haskell中添加类型级别的followdas,这样您就可以让instance Functor Music表示类似于

instance Functor (\a -> Duo (Maybe (Concurrent a)) (Maybe (Sequential a)))

但这有一些严重的问题。添加它的简单方法导致您需要在类型检查期间进行高阶统一,这是不可判定的。

相关问题