Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.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 将(a1,b1)和(a2,b2)映射为(a1和a2,b1和b2)_Haskell_Monads_Applicative_Monoids - Fatal编程技术网

Haskell 将(a1,b1)和(a2,b2)映射为(a1和a2,b1和b2)

Haskell 将(a1,b1)和(a2,b2)映射为(a1和a2,b1和b2),haskell,monads,applicative,monoids,Haskell,Monads,Applicative,Monoids,我记得这是非常基本的,甚至可以通过类似lambda的(\a b->(fst a+fst b,snd a+snd b))(1,2)(3,4)简单地进行模式匹配。然而,我认为Haskell标准库应该提供一些方法来完成这样的事情。(a,b)类型的mappend作为幺半群的定义看起来非常相似。但执行以下操作不起作用: (1,2) `mappend` (3,4) 哈斯凯尔有没有办法添加两个二元组?数字是幺半群,这不是问题所在。问题是,有两种不同的、同样好的方法,它们是幺半群——加法只有一种,另一种是乘法

我记得这是非常基本的,甚至可以通过类似lambda的
(\a b->(fst a+fst b,snd a+snd b))(1,2)(3,4)
简单地进行模式匹配。然而,我认为Haskell标准库应该提供一些方法来完成这样的事情。
(a,b)
类型的
mappend
作为幺半群的定义看起来非常相似。但执行以下操作不起作用:

(1,2) `mappend` (3,4)

哈斯凯尔有没有办法添加两个二元组?

数字是幺半群,这不是问题所在。问题是,有两种不同的、同样好的方法,它们是幺半群——加法只有一种,另一种是乘法。因此,标准库决定根本不提供幺半群实例,我认为这是一个好的决定

Haskell允许newtype包装器中的打包类型在不影响基础类型的情况下选择实例。两个不同的幺半群实例在base中可用:

Prelude Data.Monoid> case (Sum 1, Sum 2)<>(Sum 3, Sum 4) of (Sum a, Sum b) -> (a,b)
(4,6)
但是,如果元组元素的类型已经固定

Prelude Data.Monoid> let [a,b,c,d] = [1,2,3,4] :: [Int]
Prelude Data.Monoid> case (a,b) <> (c,d) of (Sum x, Sum y) -> (x,y) :: (Int,Int) 
<interactive>:6:25:
    Couldn't match expected type ‘Int’ with actual type ‘Sum Int’
    In the pattern: Sum x
    In the pattern: (Sum x, Sum y)
    In a case alternative: (Sum x, Sum y) -> (x, y) :: (Int, Int)
甚至更简洁、更不依赖本地签名的方法也可以使用:

…然而,正如我现在相当惊讶地发现的那样,
newtype
库没有提供实现此功能所必需的tuple实例。您可以自己定义它:

> :set -XFunctionalDependencies -XUndecidableInstances
> instance (Newtype a α, Newtype b β) => Newtype (a,b) (α,β) where {pack=pack***pack; unpack=unpack***unpack}

如果您确实只需要加法幺半群,我建议您使用专用类进行加法:


这也可以用一些简单、愚蠢但奇特的方法来实现(尽管这种方法需要将Haskell转换为Lisp)


如果您允许我忽略
Monoid
在您的问题中的作用,这里有两种表达它的方法,这是
Applicative
Bifunctor
的一个非常简单的概括:

GHCi> import Data.Biapplicative
GHCi> :t bimap
bimap :: Bifunctor p => (a -> b) -> (c -> d) -> p a c -> p b d
GHCi> :t (<<*>>)
(<<*>>) :: Biapplicative p => p (a -> b) (c -> d) -> p a c -> p b d
GHCi> bimap (+) (+) (1,2) <<*>> (3,4)
(4,6)
GHCi> :t biliftA2
biliftA2
  :: Biapplicative w =>
     (a -> b -> c) -> (d -> e -> f) -> w a d -> w b e -> w c f
GHCi> biliftA2 (+) (+) (1,2) (3,4)
(4,6)
GHCi>导入数据。双应用
GHCi>:t bimap
bimap::Bifunctor p=>(a->b)->(c->d)->p a c->p b d
GHCi>:t()
()::双应用程序p=>p(a->b)(c->d)->p a c->p b d
GHCi>bimap(+)(+)(1,2)(3,4)
(4,6)
GHCi>:t biliftA2
胆汁2
::双应用程序w=>
(a->b->c)->(d->e->f)->w a d->w b e->w c f
GHCi>biliftA2(+)(+)(1,2)(3,4)
(4,6)

您可以使用
Sum
newtype对
Monoid
实例进行编码。数字通常可以属于多个
Monoid
实例,因此默认情况下没有为它们定义一个实例。你必须选择你想用哪一个。我可能还建议您查看
控件。Arrow
模块,因为您想做的事情可以用这些组合符很容易地描述。看起来像我的答案,但我觉得这比简单地使用lambda有点复杂:/您也不需要到处重复
Sum
,因为有一个
实例(Num a)=>Num(Sum a)
,因此只要不模棱两可,推理就可以得到它。例如,(Sum x,Sum y)->(x,y)@JonPurdy对,
Num
实例如果元组不只是包含数字文本(这几乎肯定不是实际的用例)的
case(1,2)(3,4))但是变量的类型已经是刚性的。如果调用函数,例如
bisum
getBisum
,而不是使用后缀语法,则使用的括号会少得多。
Prelude Data.Monoid> :m +Control.Newtype
Prelude Data.Monoid Control.Newtype> :m +Control.Arrow
Prelude Data.Monoid Control.Newtype Control.Arrow> :simpleprompt 
> ala (Sum***Sum) foldMap [(1,2), (3,4)]
(4,6)
> :set -XFunctionalDependencies -XUndecidableInstances
> instance (Newtype a α, Newtype b β) => Newtype (a,b) (α,β) where {pack=pack***pack; unpack=unpack***unpack}
Prelude Data.AdditiveGroup> (1,2)^+^(3,4)
(4,6)
{-# LANGUAGE PostfixOperators #-}

import Data.Bifunctor (bimap)
import Data.Semigroup (Sum (..), (<>))

(+?) :: (a, b) -> (Sum a, Sum b)
(+?) = bimap Sum Sum

(+!) :: (Sum a, Sum b) -> (a, b)
(+!) = bimap getSum getSum
ghci> (( ((1,2) +?) <> ((3,4) +?)) +!)
(4,6)
GHCi> import Data.Biapplicative
GHCi> :t bimap
bimap :: Bifunctor p => (a -> b) -> (c -> d) -> p a c -> p b d
GHCi> :t (<<*>>)
(<<*>>) :: Biapplicative p => p (a -> b) (c -> d) -> p a c -> p b d
GHCi> bimap (+) (+) (1,2) <<*>> (3,4)
(4,6)
GHCi> :t biliftA2
biliftA2
  :: Biapplicative w =>
     (a -> b -> c) -> (d -> e -> f) -> w a d -> w b e -> w c f
GHCi> biliftA2 (+) (+) (1,2) (3,4)
(4,6)