dictionary - Haskell:如何在自己的地图数据类型上实现应用函子?
问题描述
我对 Haskell 很陌生,我在 Haskell 中编写了一个数据类型来表示间隔图。
这意味着什么?简而言之:一种地图数据类型,它为每个可能的键返回一个值(在我的例子中简单地说 [0..])。
然后你插入“序列”,就像我希望我的地图保持从 7 到 23 'b' 所以键 0 到 6 将是初始值,例如 'a' 和 7 到 23 将是 'b' 和 24 并且正在进行将是 'a ' 再次等。
我设法编写了数据类型、获取和插入函数以及仿函数版本。
但我无法让应用函子版本工作。这个想法是将键值设置为 [0..] 并只处理这些值。
这是我的代码,感谢您提供的任何帮助!
-- Building an interval map data structure in haskell
data IntervalMap k v = IntervalMap {keys :: [k] , values :: [v]} | Empty deriving Show
-- k = key, Typ variable
-- v = value, Typ variable
singleton :: (Enum k, Num k) => v -> IntervalMap k v
singleton v = IntervalMap{keys=[0..], values= repeat v}
-- get operator => a ! 5 = value at position 5
(!) :: Ord k => IntervalMap k v -> k -> v
(!) iMap k = snd (head (filter (\(x, y) -> x == k) (zip (keys iMap) (values iMap)) ))
-- insert a sequence into intervalMap
insert :: (Ord k, Num k, Enum k) => k -> k -> v -> IntervalMap k v -> IntervalMap k v
insert start end value iMap = IntervalMap {keys=keys iMap, values = rangeChanger (values iMap) start end value}
-- helper function to change a range of values in an intervalMap
rangeChanger :: (Num a1, Enum a1, Ord a1) => [a2] -> a1 -> a1 -> a2 -> [a2]
rangeChanger iMapValues start end value = [if (i >= start) && (i <= end) then newValue else iMapValue | (iMapValue, newValue, i) <- zip3 iMapValues (repeat value) [0..]]
-- functor instance for intervalMap
instance Functor (IntervalMap k) where
-- fmap :: (a -> b) -> f a -> f b
fmap f iMap = IntervalMap {keys=keys iMap, values= map f (values iMap) }
-- applicative functor for intervalMap
instance (Ord k, Num k, Enum k) => Applicative (IntervalMap k) where
pure k = IntervalMap{keys=[0..], values=repeat k}
_ <*> Nothing = Nothing
-- HOW TO DO?
-- class Functor functor => Applicative functor where
-- pure :: a -> functor a
-- (<*>) :: functor (a -> b) -> functor a -> functor b
-- (*>) :: functor a -> functor b -> functor b
-- (<*) :: functor a -> functor b -> functor a
解决方案
似乎您总是希望键是,例如它在您的函数[0..]
中是硬编码的。rangeChanger
如果是这样,那么它是多余的,老实说,我会把它排除在外。您可以通过像zip [0..] (values iMap)
在rangeChanger
函数中所做的那样轻松地重建它。
如果您进行了更改,那么您的IntervalMap
数据结构基本上与此处ZipList
具有应用程序实例的数据结构相同:
instance Applicative ZipList where pure x = ZipList (repeat x) liftA2 f (ZipList xs) (ZipList ys) = ZipList (zipWith f xs ys)
您会看到这没有定义 a<*>
但可以根据liftA2
:定义p <*> q = liftA2 (\f x -> f x) p q
,因此您也可以明确地为ZipList
:
ZipList fs <*> ZipList xs = ZipList (zipWith (\f x -> f x) fs xs)
编辑:我还应该提到一个区别ZipList
是你有一个类型的Empty
构造函数IntervalMap
。这使事情变得更加困难,您需要知道您的值具有某种默认值,但这通常是不可能的(并非每种类型都有默认值),因此您的类型不能是 Applicative。你真的需要那个Empty
箱子吗?
推荐阅读
- python - 如何针对 40k+ 链接优化我的网络抓取工具
- java - SpringBoot 不读取 application.properties
- oracle - sql%rowcount 属性是否在循环条件下工作?
- ios - 每当iOS Swift中的对象发生更改时如何调用notificationCenter?
- crash - 应用程序中的信号 11 (SIGSEGV)、代码 1 (SEGV_MAPERR) 没有本机代码,我无法缩小问题的原因
- javascript - Laravel - 依赖下拉错误:GET http://localhost:8888/get.employee.states?country_id=5 404(未找到)
- sql - 用户第二次购买时的累积计数
- python - 如何通过一组项目从 Pandas Dataframe 中进行选择?
- arrays - 如何将响应 API 中的数组映射到响应中的选择元素?
- python - 三类分类中的2x2混淆矩阵?