【问题标题】:Why isn't there an interval typeclass in haskell?为什么haskell中没有区间类型类?
【发布时间】:2014-12-25 08:40:34
【问题描述】:

也许我没有找对地方,但我在 Haskell 中找不到区间的类型类。在我看来,这种抽象在很多情况下都会很有用,因为在很多领域都使用了区间。

这也可以从 hackage 上实现某种区间结构 (list of interval packages) 的不同包的数量中看出。

用类型类实现不同类型的区间(开、闭、...)会不会令人困惑,还是有其他概念可以帮助我建立自己的区间,除了自己的数据类型?

【问题讨论】:

  • 为什么是一个类型类,而不仅仅是一个简单的数据类型(元组?),上面有一组(当然是受限的)函数? (嗯 - 就像 Kmett 先生 hackage.haskell.org/package/intervals-0.7.0.1/docs/… 的那个一样;))
  • 主要优点是,它适用于不同的类型?不同类型的边界(UTCTimeInt,...)没有代码重复,因为逻辑将保持不变。它也很适合OrdEq
  • @j.dog: 所有这些区间类型都是在未定义的字段类型上参数化,所以你可以只做Interval DoubleInterval UTCTimeInterval Int.. . 根本不需要上课。
  • 我不知道 - 这使它非常好用。作为仍在学习的人,Haskell 一直让我惊叹。

标签: haskell types typeclass abstraction


【解决方案1】:

您可以使用 -XFunctionalDependences-XFlexibleInstances 来执行此操作(使用此编写任何实例...)。我在下面用 cmets 写了一些代码来说明:

{-# LANGUAGE FlexibleInstances      #-}
{-# LANGUAGE FunctionalDependencies #-}

-- | Intervals with endpoints of type e.
class (Ord e) => Interval i e | i -> e where
  {-# MINIMAL inf, sup #-}
  -- lower bound ("infinimum") 
  inf :: i -> e
  -- upper bound ("supremum")
  sup :: i -> e

-- Is (X : Interval e) a valid Interval?
valid :: Interval i e => i -> Bool
valid x = sup x > inf x

-- Is (X : Interval e) an invalid Interval?
notValid :: Interval i e => i -> Bool
notValid = not . valid

-- Is (x : e) contained within (X : Interval e)
containsPoint :: Interval i e => i -> e -> Bool
x `containsPoint` p = p >= inf x && p <= sup x

-- Is (x : e) below (X : Interval e)
abovePoint :: Interval i e => i -> e -> Bool
x `abovePoint` p = p < inf x

-- Is (x : e) above (X : Interval e)
belowPoint :: Interval i e => i -> e -> Bool
x `belowPoint` p = p > sup x

-- For all (x : e) in (X : Interval e), (y : e) in (Y : Interval e),
-- x < y iff sup X < inf Y 
before :: Interval i e => i -> i -> Bool
x `before` y = sup x < inf y

-- For all (x : e) in (X : Interval e), (y : e) in (Y : Interval e),
-- x > y iff inf X > sup Y 
after :: Interval i e => i -> i -> Bool
x `after` y = inf x > sup y

-- For all (x : e) in (X : Interval e), (y : e) in (Y : Interval e),
-- x == y iff (inf X == inf Y) && (sup X == sup Y)
equals :: Interval i e => i -> i -> Bool
x `equals` y = inf x == inf y && sup x == sup y

-- For all (x : e) in (X : Interval e), (y : e) in (Y : Interval e),
-- x /= y iff (sup x < inf y) || (inf x > sup y)
nequals :: Interval i e => i -> i -> Bool
x `nequals` y = sup x < inf y || inf x > sup y

-- For all (x : e) in (X : Interval e), (y : e) in (Y : Interval e),
-- x <= y iff sup x <= inf y
eqBefore :: Interval i e => i -> i -> Bool
x `eqBefore` y = sup x <= inf y

-- For all (x : e) in (X : Interval e), (y : e) in (Y : Interval e),
-- x >= y iff inf x >= sup y
eqAfter :: Interval i e => i -> i -> Bool
x `eqAfter` y = inf x >= sup y

-- Does (X : Interval e) contain (Y : Interval e)?
contains :: Interval i e => i -> i -> Bool
x `contains` y = inf x <= inf y && sup y <= sup x

-- Is (X : Interval e) a subset of (Y : Interval e)?
isSubSetOf :: Interval i e => i -> i -> Bool
isSubSetOf = flip contains

-- Do (X : Interval e) and (Y : Interval e) overlap?
overlaps :: Interval i e => i -> i -> Bool 
x `overlaps` y = inf x <= sup y && sup x >= inf y

instance (Ord e) => Interval (e,e) e where
  inf (a,_) = a
  sup (_,b) = b

instance (Ord a) => Interval [a] a where
  inf = minimum
  sup = maximum

main :: IO ()
main = do
  putStrLn $ inf ["one","two","three"] -- will print "one"
  putStrLn $ sup ("first","second")    -- will print "second"

但是,正如评论者所指出的,这是非常不必要的。最好有类似Interval 的数据类型,而只有Interval DoubleInterval Int 等。我推荐intervals 包。

【讨论】:

    猜你喜欢
    • 2016-04-16
    • 2011-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-06
    • 1970-01-01
    • 2011-01-11
    相关资源
    最近更新 更多