Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.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
Haskell 具有类型依赖关系的多参数类_Haskell - Fatal编程技术网

Haskell 具有类型依赖关系的多参数类

Haskell 具有类型依赖关系的多参数类,haskell,Haskell,我正试图将我的聚合器类型升级到一个类,但我不知道该怎么做 我有这个: data Aggregator a b = Aggregator { aggregate :: [a] -> b } minMax = Aggregator (\xs -> (minimum xs, maximum)) 我想要的是: class Aggregator (g a b) where aggregate :: g -> [a] -> b 所以我可以这样做: data DoubleAg

我正试图将我的聚合器类型升级到一个类,但我不知道该怎么做

我有这个:

data Aggregator a b = Aggregator { aggregate :: [a] -> b }
minMax = Aggregator (\xs -> (minimum xs, maximum))
我想要的是:

class Aggregator (g a b) where
   aggregate :: g -> [a] -> b
所以我可以这样做:

data DoubleAggregator a b = DoubleAggregator ([a] -> b) ([a] -> b)

instance Aggregator (DoubleAggregator a b) where
     aggregate (DoubleAggregator f g) as = (f as, g as)

这显然不起作用。我想我需要
MultipleParamTypeClasses
FamilyTypes
,但我想不出来。我知道,在这一点上,我并不真正需要类,只需要
数据聚合器ab…
,但我仍然对如何使用类感兴趣。那么我该怎么做呢?

请注意,
DoubleAggregator
的实例类型不好,因为输出是
(b,b)
,但类声明说它必须是
b
。因此,您要么想办法将两个
b
s合并为一个,这可能是不可取的,要么让输出类型取决于聚合器类型:

{-# LANGUAGE TypeFamilies #-}

class Aggregator g where
  type Result x y z 
  aggregate :: g a b -> [a] -> Result g a b

data SingleAggregator a b = SingleAggregator ([a] -> b)
instance Aggregator SingleAggregator where 
  type Result SingleAggregator a b = b
  aggregate (SingleAggregator f) = f 

data DoubleAggregator a b = DoubleAggregator ([a] -> b) ([a] -> b)
instance Aggregator DoubleAggregator where
  type Result DoubleAggregator a b = (b,b)
  aggregate (DoubleAggregator f g) as = (f as, g as)
请注意,该类没有提到
a
b
,因为它们都可以是任意类型,并且不依赖于聚合器类型。类型
Result
是三个方面的函数:聚合器的类型和聚合器内部的类型。您的结果可能永远不会依赖于输入类型,
a
,在这种情况下,您可以编写如下内容:

class Aggregator g where
  type Result x y 
  aggregate :: g a b -> [a] -> Result g b

....

  type Result SingleAggregator b = b

....

  type Result DoubleAggregator b = (b, b)
您也可以使用
multiparamtypeclass
functionaldependences
来实现这一点,但它更复杂,类型更难阅读,因此在我看来,这是一个更糟糕的解决方案,我只考虑完整性

{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances #-}

class Aggregator g a b r | g a b -> r where
  aggregate :: g a b -> [a] -> r

data SingleAggregator a b = SingleAggregator ([a] -> b)
instance Aggregator SingleAggregator a b b where 
  aggregate (SingleAggregator f) = f 

data DoubleAggregator a b = DoubleAggregator ([a] -> b) ([a] -> b)
instance Aggregator DoubleAggregator a b (b,b) where
  aggregate (DoubleAggregator f g) as = (f as, g as)

主要区别在于功能依赖性:
|gab->r
;也就是说,对于某些
gab
,存在一个唯一的
r

注意,
DoubleAggregator
的实例类型不好,因为输出是
(b,b)
,但是类声明说它必须是
b
。因此,您要么想办法将两个
b
s合并为一个,这可能是不可取的,要么让输出类型取决于聚合器类型:

{-# LANGUAGE TypeFamilies #-}

class Aggregator g where
  type Result x y z 
  aggregate :: g a b -> [a] -> Result g a b

data SingleAggregator a b = SingleAggregator ([a] -> b)
instance Aggregator SingleAggregator where 
  type Result SingleAggregator a b = b
  aggregate (SingleAggregator f) = f 

data DoubleAggregator a b = DoubleAggregator ([a] -> b) ([a] -> b)
instance Aggregator DoubleAggregator where
  type Result DoubleAggregator a b = (b,b)
  aggregate (DoubleAggregator f g) as = (f as, g as)
请注意,该类没有提到
a
b
,因为它们都可以是任意类型,并且不依赖于聚合器类型。类型
Result
是三个方面的函数:聚合器的类型和聚合器内部的类型。您的结果可能永远不会依赖于输入类型,
a
,在这种情况下,您可以编写如下内容:

class Aggregator g where
  type Result x y 
  aggregate :: g a b -> [a] -> Result g b

....

  type Result SingleAggregator b = b

....

  type Result DoubleAggregator b = (b, b)
您也可以使用
multiparamtypeclass
functionaldependences
来实现这一点,但它更复杂,类型更难阅读,因此在我看来,这是一个更糟糕的解决方案,我只考虑完整性

{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances #-}

class Aggregator g a b r | g a b -> r where
  aggregate :: g a b -> [a] -> r

data SingleAggregator a b = SingleAggregator ([a] -> b)
instance Aggregator SingleAggregator a b b where 
  aggregate (SingleAggregator f) = f 

data DoubleAggregator a b = DoubleAggregator ([a] -> b) ([a] -> b)
instance Aggregator DoubleAggregator a b (b,b) where
  aggregate (DoubleAggregator f g) as = (f as, g as)

主要区别在于功能依赖性:
|gab->r
;也就是说,对于某些
gab
,存在一个唯一的
r

除了使用类型族或函数依赖项(如user2407038的回答中所示),另一种选择是使用

这是一个更好还是更差的选择取决于您的具体用例,但我发现它在实践中比类型类扩展简单得多

如果需要,GADT方法还允许您完全抛弃类型类,只使用一个代数类型

data Aggregator a b where
    SingleAggregator :: ([a] -> b) -> Aggregator a b
    DoubleAggregator :: ([a] -> b) -> ([a] -> b) -> Aggregator a (b, b)

aggregate :: Aggregator a b -> [a] -> b
aggregate (SingleAggregator f)   as = f as
aggregate (DoubleAggregator f g) as = (f as, g as)
然而,实现这一点的最“Haskell-y”的方法可能是只使用一个
聚合器
newtype,并使其与
Applicative
type类组合。例如:

import Control.Applicative

newtype Aggregator a b = Aggregator { aggregate :: [a] -> b }

instance Functor (Aggregator a) where
    fmap f (Aggregator g) = Aggregator (f . g)

instance Applicative (Aggregator a) where
    pure = Aggregator . const
    Aggregator f <*> Aggregator x = Aggregator $ f <*> x
然后使用
Applicative
界面将它们组合成更复杂的聚合器

minMax = liftA2 (,) minAgg maxAgg

除了使用类型族或函数依赖项(如user2407038的回答中所示),另一种选择是使用

这是一个更好还是更差的选择取决于您的具体用例,但我发现它在实践中比类型类扩展简单得多

如果需要,GADT方法还允许您完全抛弃类型类,只使用一个代数类型

data Aggregator a b where
    SingleAggregator :: ([a] -> b) -> Aggregator a b
    DoubleAggregator :: ([a] -> b) -> ([a] -> b) -> Aggregator a (b, b)

aggregate :: Aggregator a b -> [a] -> b
aggregate (SingleAggregator f)   as = f as
aggregate (DoubleAggregator f g) as = (f as, g as)
然而,实现这一点的最“Haskell-y”的方法可能是只使用一个
聚合器
newtype,并使其与
Applicative
type类组合。例如:

import Control.Applicative

newtype Aggregator a b = Aggregator { aggregate :: [a] -> b }

instance Functor (Aggregator a) where
    fmap f (Aggregator g) = Aggregator (f . g)

instance Applicative (Aggregator a) where
    pure = Aggregator . const
    Aggregator f <*> Aggregator x = Aggregator $ f <*> x
然后使用
Applicative
界面将它们组合成更复杂的聚合器

minMax = liftA2 (,) minAgg maxAgg

我知道您特别有兴趣用类处理这个问题,但这听起来更像是一个
折叠问题,即使您只是使用
数据聚合器AB,看起来空列表不太可能正确处理。您可能想研究
幺半群和折叠?我知道您特别有兴趣用类来处理这个问题,但这听起来更像是
折叠问题,即使您只是使用
数据聚合器AB,看起来空列表不太可能正确处理。你可能想看看
幺半群和折叠?我真的很喜欢!谢谢(我可能终于明白了GADT的用途了。)。谢谢我还添加了一个使用应用程序的示例,我认为这是此类问题中最常用的模式。我真的很喜欢!谢谢(我可能终于明白了GADT的用途了。)。谢谢我还添加了一个使用应用程序的示例,我认为这是此类问题中最常用的模式。