Haskell新手的类型

gar*_*lfo 9 haskell

我是Haskell的新手(更常见的是函数式编程),所以请原谅我这是非常基本的东西.为了获得更多的品味,我尝试在Haskell中实现一些我正在研究的算法.我有一个简单的模块Interval,在线上实现间隔.它包含类型

data Interval t = Interval t t
Run Code Online (Sandbox Code Playgroud)

辅助功能

makeInterval :: (Ord t) => t -> t -> Interval t  
makeInterval l r  | l <= r    = Interval l r  
                  | otherwise = error "bad interval"  
Run Code Online (Sandbox Code Playgroud)

和一些关于间隔的效用函数.

在这里,我的兴趣在于多维间隔(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]    
Run Code Online (Sandbox Code Playgroud)

允许进行不同的健全性检查,例如

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 
Run Code Online (Sandbox Code Playgroud)

我现在终于明白了!但是一些功能自然与多个间隔和轨道间隔有关.例如,函数order将返回多个间隔或轨道间隔中的间隔数.我能做什么?添加

-- Dimensional interval
data DInterval t = MIntervalStuff (MInterval t) | TIntervalStuff (TInterval t)
Run Code Online (Sandbox Code Playgroud)

并没有多大帮助,因为,如果我理解得很好(如果我错了,请纠正我),我必须写

order :: DInterval t -> Int
order (MIntervalStuff (MInterval is)) = length is
order (TIntervalStuff (TInterval is)) = length is
Run Code Online (Sandbox Code Playgroud)

并呼吁order作为order (MIntervalStuff is)order (TIntervalStuff is)is是一个MInterval或一个TInterval.不是很好,看起来很奇怪.我都不想复制该函数(我有许多与多个和轨道间隔有关的函数,以及一些其他d区间定义,例如等长多个和轨道间隔).

我感觉我完全错了,并且错过了关于Haskell类型的一些重要观点(和/或在这里不能忘记OO编程).所以,这是一个新手问题,Haskell处理这种情况的最佳方法是什么?我是否必须忘记介绍MIntervalTInterval仅使用一种类型?

非常感谢你的帮助,

Garulfo

Joh*_*n L 5

编辑:这与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 = ..
Run Code Online (Sandbox Code Playgroud)

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

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

我还改变了makeMInterval函数的实现; Maybe为这样的函数返回一个比调用错误更惯用的东西.

关于Maybe的更多解释:

让我们检查一下你的功能makeInterval.该函数应该采用Interval列表,如果符合条件,则返回多个间隔,否则返回轨道间隔.这种解释导致类型:

makeInterval :: (Ord t) =>
  [I.Interval t] ->
  Either (DInterval TInterval t) (DInterval MInterval t)
Run Code Online (Sandbox Code Playgroud)

现在我们有了类型,我们如何实现呢?我们想重新使用我们的makeMInterval函数.

makeInterval is = maybe
                   (Left $ DInterval TInterval is)
                   Right
                   (makeMInterval is)
Run Code Online (Sandbox Code Playgroud)

该函数maybe有三个参数:默认的b使用,如果可能就是Nothing,一个函数a -> b如果也许就是Just aMaybe a.它返回默认值或将函数应用于Maybe值的结果.

我们的默认值是轨道间隔,因此我们为第一个参数创建一个左轨道间隔.如果可能是Just (DInterval MInterval t),则多重间隔已经存在,所以所有必要的是将它粘在两者的右侧.最后,makeMInterval用于创建多个间隔.


Rob*_*kop 0

考虑使用类型类来显示不同类型之间的相似性。有关类和重载的帮助,请参阅 haskell 教程 [1]。

[1]:http://www.haskell.org/tutorial/classes.html haskell教程