首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >这个功能可以用Haskell的类型系统实现吗?

这个功能可以用Haskell的类型系统实现吗?
EN

Stack Overflow用户
提问于 2011-10-10 01:12:21
回答 3查看 1.9K关注 0票数 18

在Scala中,集合上的高阶操作总是返回上下文中可能的最佳类型。例如,在BitSet的情况下,如果将in映射到in,则会得到一个BitSet,但如果将in映射到字符串,则会得到一个通用的Set。类似地,如果您使用生成一对的函数对Map执行map操作,则会返回一个Map。否则你会得到一个简单的Iterable。map结果的静态类型和运行时表示都取决于传递给它的函数的结果类型。

代码语言:javascript
复制
scala> Map(2 -> 'a', 6 -> 'b') map { case (k, v) => (k + 1, v.toString) }
res0: scala.collection.immutable.Map[Int,java.lang.String] = Map(3 -> a, 7 -> b)

scala> Map(2 -> 'a', 6 -> 'b') map { _._1 }
res1: scala.collection.immutable.Iterable[Int] = List(2, 6)

scala> import collection.immutable.BitSet
import collection.immutable.BitSet

scala> BitSet(2, 44, 93).map(1 +)
res3: scala.collection.immutable.BitSet = BitSet(3, 45, 94)

scala> BitSet(2, 44, 93).map(_ + "hola")
res4: scala.collection.immutable.Set[String] = Set(2hola, 44hola, 93hola)

是否有可能在Haskell的类型系统中实现相同的功能?如果是,是如何实现的?以上代码片段中的示例的Haskell翻译将非常受欢迎。:-)

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-10-10 02:15:17

我不认为您的第一个示例是非常Haskell-y的,因为您重载了相同的名称来做两个非常不同的事情。在Haskell中,当您将一个函数映射到某个容器上时,您希望得到相同的容器类型。事实上,这在Haskell中非常常见,以至于有一个类型类,Functor,它封装了这个模式。

Haskell中的所有形式的重载都归结为使用类型类,虽然您可以使用这些类来实现类似的功能,但它将是非常人为的,并且与仅使用仅做您想要的一件事的普通函数相比没有多大用处。

代码语言:javascript
复制
Prelude> import qualified Data.Map as M
Prelude Data.Map> let m = M.fromList [(2, 'a'), (6, 'b')]
Prelude Data.Map> M.map show $ M.mapKeys (+1) m
fromList [(3,"'a'"),(7,"'b'")]
Prelude Data.Map> M.keys m
[2,6]

我认为您的第二个示例与Haskell更相关,因为它更多地是关于根据包含的类型选择最有效的数据结构实现,我怀疑使用type families应该不会太难,但我对这些不太熟悉,所以我会让其他人尝试回答这一部分。

票数 11
EN

Stack Overflow用户

发布于 2011-10-10 02:42:21

我非常同意hammar的观点,但这里有一种方法:

代码语言:javascript
复制
{-# LANGUAGE MultiParamTypeClasses, TypeFamilies, FlexibleInstances #-}

import Prelude hiding (map)

import qualified Data.Map as M
import qualified Data.IntSet as I
import qualified Data.Set as S

type family Elem c :: *
type instance Elem (M.Map k v) = (k, v)
type instance Elem I.IntSet = Int
type instance Elem (S.Set a) = a

class Map c o where
  type Result c o :: *
  map :: (Elem c -> o) -> c -> Result c o

instance Map I.IntSet Int where
  type Result I.IntSet Int = I.IntSet
  map = I.map

instance Map I.IntSet String where
  type Result I.IntSet String = S.Set String
  map f = S.fromList . fmap f . I.toList

instance (Ord k, Ord k1) => Map (M.Map k v) (k1, v1) where
  type Result (M.Map k v) (k1, v1) = M.Map k1 v1
  map f = M.fromList . fmap f . M.toList

instance (Ord k) => Map (M.Map k v) Int where
  type Result (M.Map k v) Int = [Int]
  map f = fmap f . M.toList

这就是它的实际作用:

代码语言:javascript
复制
*Main> map fst (M.fromList [(2::Int, 'a'), (6, 'b')])
[2,6]
*Main> map (\(k, v) -> (k + 1, show v)) (M.fromList [(2, 'a'), (6, 'b')])
fromList [(3,"'a'"),(7,"'b'")]
*Main> :t it
it :: M.Map Integer [Char]

理想情况下,您会希望这样做:

代码语言:javascript
复制
instance (Ord k) => Map (M.Map k v) a where
  type Result (M.Map k v) a = [a]
  map f = fmap f . M.toList

但该实例与pairs的实例冲突。因此,没有好的方法为每个其他类型提供一个实例。

票数 8
EN

Stack Overflow用户

发布于 2011-10-10 02:43:00

补充一下hammar:我认为第二个例子是不可能的,因为有隐式的类型转换。

为了便于讨论,忽略这一点,类型签名是什么样子的:

代码语言:javascript
复制
setmap :: (Set a, Set b) => a e -> (e -> f) -> b f 

所以,是的,这是可以想象的,但前提是可能需要指定返回类型。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7705119

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档