Haskell 新手类型

标签 haskell

我对 Haskell 完全陌生(更普遍的是函数式编程),所以如果这真的是基本的东西,请原谅我。为了获得更多的体验,我尝试在 Haskell 中实现一些我正在研究的算法。我有一个简单的模块 Interval实现就行的间隔。它包含类型

data Interval t = Interval t t

辅助函数
makeInterval :: (Ord t) => t -> t -> Interval t  
makeInterval l r  | l <= r    = Interval l r  
                  | otherwise = error "bad interval"  

以及一些关于区间的实用函数。

在这里,我的兴趣在于多维区间(d 区间),即由 d 区间组成的那些对象。我想分别考虑 d 间隔,它是线上 d 个不相交间隔的并集(多个间隔)与 d 条独立线上的 d 间隔的并集(轨道间隔)。考虑到不同的算法处理,我认为最好有两种不同的类型(即使两者都是这里的区间列表),例如
import qualified Interval as I

-- Multilple interval  
newtype MInterval t = MInterval [I.Interval t]  

   -- Track interval  
newtype TInterval t = TInterval [I.Interval t]    

允许进行不同的健全性检查,例如
makeMInterval :: (Ord t) => [I.Interval t] -> MInterval t
makeMInterval is = if foldr (&&) True [I.precedes i i' | (i, i') <- zip is (tail is)]  
                   then (MInterval is)
                   else error "bad multiple interval"


makeTInterval :: (Ord t) => [I.Interval t] -> TInterval t
makeTInterval  = TInterval 

我现在进入正题,终于!但是有些函数自然会同时关注多个区间和轨道区间。例如,函数 order将返回多个间隔或跟踪间隔中的间隔数。我能做些什么?添加
-- Dimensional interval
data DInterval t = MIntervalStuff (MInterval t) | TIntervalStuff (TInterval t)

没有多大帮助,因为如果我理解得很好(如果我错了,请纠正我),我将不得不写
order :: DInterval t -> Int
order (MIntervalStuff (MInterval is)) = length is
order (TIntervalStuff (TInterval is)) = length is

并调用orderorder (MIntervalStuff is)order (TIntervalStuff is)isMIntervalTInterval .不是很好,看起来很奇怪。我也不想复制这个函数(我有很多函数都与多重和轨道间隔有关,以及其他一些 d 间隔定义,例如等长多重和轨道间隔)。

我觉得我完全错了,错过了一些关于 Haskell 类型的重要观点(和/或在这里不能忘记关于 OO 编程的足够多的内容)。所以,一个相当新手的问题,在 Haskell 中处理这种情况的最佳方法是什么?我必须忘记介绍MInterval吗?和 TInterval只选择一种类型?

非常感谢你的帮助,

加鲁尔福

最佳答案

编辑:这与 sclv 的答案相同;他的链接提供了有关此技术的更多信息。

这种方法怎么样?

data MInterval = MInterval --multiple interval
data TInterval = TInterval --track interval

data DInterval s t = DInterval [I.Interval t]

makeMInterval :: (Ord t) => [I.Interval t] -> Maybe (DInterval MInterval t)
makeMInterval is = if foldr (&&) True [I.precedes i i' | (i, i') <- zip is (tail is)]
  then Just (DInterval is)
  else Nothing

order :: DInterval s t -> Int
order (DInterval is) = length is

equalOrder :: DInterval s1 t -> DInterval s2 t -> Bool
equalOrder i1 i2 = order i1 == order i2

addToMInterval :: DInterval MInterval t -> Interval t -> Maybe (DInterval MInterval t)
addToMInterval = ..

这里类型 DInterval 表示多维区间,但它需要一个额外的类型参数作为幻像类型。这个额外的类型信息允许类型检查器区分不同类型的间隔,即使它们具有完全相同的表示。

您获得了原始设计的类型安全性,但您的所有结构都共享相同的实现。至关重要的是,当间隔的类型无关紧要时,您可以不指定它。

我还更改了您的 makeMInterval 函数的实现;返回 Maybe对于这样的函数,比调用错误更惯用。

关于可能的更多解释:

让我们检查一下你的函数 makeInterval .这个函数应该获取一个间隔列表,如果它们满足条件,则返回一个倍数间隔,否则返回一个跟踪间隔。这种解释导致类型:
makeInterval :: (Ord t) =>
  [I.Interval t] ->
  Either (DInterval TInterval t) (DInterval MInterval t)

现在我们有了类型,我们如何实现它?我们想重用我们的 makeMInterval 函数。
makeInterval is = maybe
                   (Left $ DInterval TInterval is)
                   Right
                   (makeMInterval is)

函数maybe接受三个参数:默认 b如果 Maybe 是 Nothing 时使用, 一个函数 a -> b如果 Maybe 是 Just a , 和 Maybe a .它返回默认值或将函数应用于 Maybe 值的结果。

我们的默认值是轨道间隔,因此我们为第一个参数创建一个左轨道间隔。如果可能是 Just (DInterval MInterval t) ,多重区间已经存在,所以只需将其粘贴到任一区间的右侧即可。最后,makeMInterval用于创建多个区间。

关于Haskell 新手类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4664429/

相关文章:

haskell - Yesod 的莎士比亚模板(哈姆雷特)和 IO

haskell - 返回该宽度和高度的网格中每个可能坐标的列表

haskell - 等效于具有停止条件的发电机的 Haskell

haskell - 是否可以手动更新行为的值? (功能响应式(Reactive)编程,三便士)

string - 如何在不使用像 MissingH 这样的外部库的情况下,用 Haskell 中的另一个替换字符串的子字符串?

haskell - Alex right_ctx 行尾 ($) 在文件末尾卡住

linux - 为什么 `stack --version` 显示的版本与安装的版本不同?

haskell - 如何理解 "ap = liftM2 id"的类型推断?

python - 在 pypandoc (pandoc) 中将较大的 HTML 文件转换为 docx 时出现问题

haskell - 因为没有 Main 模块,所以不会产生输出