Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 此功能是否可以通过Haskell';s型系统?_Scala_Haskell_Programming Languages_Functional Programming_Type Systems - Fatal编程技术网

Scala 此功能是否可以通过Haskell';s型系统?

Scala 此功能是否可以通过Haskell';s型系统?,scala,haskell,programming-languages,functional-programming,type-systems,Scala,Haskell,Programming Languages,Functional Programming,Type Systems,在Scala中,集合上的高阶操作总是返回上下文中可能的最佳类型。例如,在位集的情况下,如果将int映射到int,则会得到位集,但如果将int映射到字符串,则会得到常规集。类似地,如果您使用一个生成一对的函数mapamap,那么您将得到一个map。否则您将得到一个简单的Iterable。映射结果的静态类型和运行时表示形式都取决于传递给它的函数的结果类型 scala> Map(2 -> 'a', 6 -> 'b') map { case (k, v) => (k + 1, v

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

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版本,将不胜感激。:-)

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

Haskell中所有形式的重载归结为使用类型类,虽然您可以使用这些类型类来实现类似的功能,但是如果只使用简单的函数来完成您想要的一件事情,那么这将是非常人为的,并且没有多大用处

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更相关,因为它更多的是基于包含的类型选择最有效的数据结构实现,我认为这应该不太难使用,但我对这些不太熟悉,所以我会让其他人来回答这一部分。

我非常同意哈马尔的观点,但有一种方法可以做到这一点:

{-# 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
这就是它的作用:

*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]
理想情况下,您希望这样做:

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的实例冲突。因此,没有好的方法为每一个其他类型提供一个实例。

添加到hammar:我认为第二个示例目前是不可能的,因为存在隐式类型转换

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

setmap :: (Set a, Set b) => a e -> (e -> f) -> b f 
因此,是的,这是可以想象的,但前提是可能需要指定返回类型