代数数据类型(意图)名称冲突..怎么样?

问题描述 投票:0回答:2

我有想法在Haskell中实现我自己的小音乐理论模块。

从笔记(Note)开始是有意义的,然后我遇到了这个讨厌的句法问题,我不知道真正的Haskellers如何处理它。

data Note = Sharp NoteS | Flat NoteF deriving (Show)

data NoteS = 
    C | SC | D | SD | E | F | SF | G | SG | B
    deriving (Ord,Show,Eq)

data NoteF = 
    C | FD | D | FE | E | F | FG | G | FB | B
    deriving (Ord,Show,Eq)

instance Eq Note where
    (==) (NoteS n1) (NoteS n2) = n1 == n2
    (==) (NoteF n1) (NoteF n2) = n1 == n2
    (==) (NoteS n1) (NoteF n2) = ???
    (==) (NoteF n1) (NoteS n2) = ???
    ...

flatToSharp :: Note -> NoteS
sharpToFlat :: Note -> NoteF

大多数人可能知道,尖锐的C和平坦的D一般是同义词,但有时候根据上下文优先使用其中一个或另一个。所以我希望使用NoteSNoteF都是Ord的例子(例如用于区间计算)。但在两种表示中,普通音符(C,D,E,F ......)在两种类型中都具有相同的名称。

现在我可以想办法“破解”这个句法问题。但它要么具有丑陋的语法含义或运行时间含义(例如使用字符串而不是类型,大量的测试和错误检查,......)。

所以这是我对Haskell专业人员的问题......如果没有对Haskell的这个“命名空间”问题做出太多让步,我将如何按照我的想法来做这件事?

我试过{-# LANGUAGE DuplicateRecordFields #-},但显然对工会没有帮助。

haskell ghc
2个回答
7
投票

如果必须保留数据表示,那么Haskell中的标准命名空间机制就是模块。所以你可以写

module Sharps where data NoteS = ...

module Flats where data NoteF = ...

module Main where
import Sharps as S
import Flats as F

(当然,不要忘记,对于GHC,每个模块必须在其自己的文件中使用适当的文件名。)然后,在Main中,您可以引用Sharps.CS.C来获取NoteS构造函数,并使用Flats.CF.C来获取NoteF构造函数。

但我可以提出不同的解决方案吗?命名自然音符怎么样,只需要一种记录你从那里变得多么尖锐或平坦的类型?毕竟,你肯定会想要处理双锐利和双重平底鞋,我敢肯定。所以:

data Natural = A | B | C | D | E | F | G
data Note = Note
    { natural :: Natural
    , offset :: Int -- positive for sharp, negative for flat, say
    }

(您还可以选择许多其他数据表示。)


5
投票

另一个想法是使用模式同义词。您可以使用一种表示注释的类型,也可以使用同义词重命名其中一些注释。

https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#pattern-synonyms

{-# LANGUAGE PatternSynonym #-}

data Note = C | SC | D | SD | E | F | SF | G | SG | B

pattern FD = SC
pattern FE = SD
pattern FG = SF
pattern FB = SG
© www.soinside.com 2019 - 2024. All rights reserved.