Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.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 对元组的所有值进行排序的任何内置fmap?_Haskell - Fatal编程技术网

Haskell 对元组的所有值进行排序的任何内置fmap?

Haskell 对元组的所有值进行排序的任何内置fmap?,haskell,Haskell,现在我有一个小助手: both f (one,two) = (f one , f two) 然后我无聊地想知道fmap是否“迭代”元组,所以我问GHCi: fmap reverse ("aA","bB") 结果是: ("aA","Bb") 奇怪!所以元组上fmap的语义似乎是“将func应用于snd”,如果你愿意的话 我应该使用base或Prelude中的任何内容,而不是我自己的两个?Hoogle给出了,或者我分析错了。关于元组中两个元素的“映射”,最好的方法是bimap::Bifunct

现在我有一个小助手:

both f (one,two) = (f one , f two)
然后我无聊地想知道
fmap
是否“迭代”元组,所以我问GHCi:

fmap reverse ("aA","bB")
结果是:

("aA","Bb")
奇怪!所以元组上fmap的语义似乎是“将func应用于snd”,如果你愿意的话

我应该使用
base
Prelude
中的任何内容,而不是我自己的
两个
?Hoogle给出了,或者我分析错了。

关于元组中两个元素的“映射”,最好的方法是
bimap::Bifunctor p=>(a->b)->(c->d)->pac->pad
(现在在
base
中定义)。有了它,你就可以写作了

ghci> bimap reverse reverse ("aA","bB")
("Aa","Bb")
ghci> (reverse *** reverse) ("aA","bB")
("Aa","Bb")
或者,您可以使用中定义的
(***)::Arrow a=>ab c->ab'c'->a(b,b')(c,c')
(特别是使用
Arrow(->)
实例)。有了它,你就可以写作了

ghci> bimap reverse reverse ("aA","bB")
("Aa","Bb")
ghci> (reverse *** reverse) ("aA","bB")
("Aa","Bb")
然而,如果您试图同时映射一个元组的两个元素,那么您可能正在寻找一种将两个
a
类型的值组合在一起的抽象。如果是这种情况,我建议您在
(a,a)
周围使用
newtype
。然后,您可以打开
-XDeriveFunctor
扩展,如下所示

ghci> :set -XDeriveFunctor
ghci> newtype Pair a = Pair (a,a) deriving (Show,Functor)
ghci> fmap reverse (Pair ("aA","bB"))
Pair ("Aa","Bb")

你需要考虑完整的类型。在类型
(a,b)
中,与a s
(,)a b
相同,函子是
(,)a
。因此我们得到

fmap :: (b -> c) -> (,) a b -> (,) a c
这表明第一个组件不受
fmap
的影响

> fmap reverse (True,"bB")
(True,"Bb")
你可能在想另一个函子

-- user-defined
data Pair a = Pair a a deriving Functor
我们有

fmap :: (b -> c) -> Pair b -> Pair c
影响两个组件,但此类型不是常规元组类型

奖金谜题:出于同样的原因

> length (1,2)
1

对于这个特定的示例来说,这无疑是一个过度的操作,它不在base中,但大多数通用编程库都允许您这样做。例如:


正如亚历克所指出的,
bimap
适合成对使用。如果您想更普遍地处理元组,一个选项是使用类。下面这篇文章的灵感来自于
lens
(特别是)中的一些想法,但我认为它与那里的任何东西都不太一样

{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}

module Tuplish where
import Data.Functor.Identity (Identity (..))
import Data.Profunctor.Unsafe ((#.), (.#))

class Tuply s t a b | s -> a, t -> b, s b -> t, t a -> s where
  ttraverse :: Applicative f => (a -> f b) -> s -> f t

mapTuple :: Tuply s t a b => (a -> b) -> (s -> t)
mapTuple = (runIdentity .) #. ttraverse .# (Identity .)


instance (a1 ~ a, a2 ~ a, b1 ~ b, b2 ~ b)
    => Tuply (a1, a2) (b1, b2) a b where
  ttraverse f (x,y) = (,) <$> f x <*> f y

instance (a1 ~ a, a2 ~ a, a3 ~ a, b1 ~ b, b2 ~ b, b3 ~ b)
    => Tuply (a1,a2,a3) (b1,b2,b3) a b where
  ttraverse f (x,y,z) = (,,) <$> f x <*> f y <*> f z

instance (a1 ~ a, a2 ~ a, a3 ~ a, a4 ~ a, b1 ~ b, b2 ~ b, b3 ~ b, b4 ~ b)
    => Tuply (a1,a2,a3,a4) (b1,b2,b3,b4) a b where
  ttraverse f (x,y,z,w) = (,,,) <$> f x <*> f y <*> f z <*> f w

instance (a1 ~ a, a2 ~ a, a3 ~ a, a4 ~ a, a5 ~ a,
          b1 ~ b, b2 ~ b, b3 ~ b, b4 ~ b, b5 ~ b)
    => Tuply (a1,a2,a3,a4,a5) (b1,b2,b3,b4,b5) a b where
  ttraverse f (x,y,z,w,u) = (,,,,) <$> f x <*> f y <*> f z <*> f w <*> f u

instance (a1 ~ a, a2 ~ a, a3 ~ a, a4 ~ a, a5 ~ a, a6 ~ a,
          b1 ~ b, b2 ~ b, b3 ~ b, b4 ~ b, b5 ~ b, b6 ~ b)
    => Tuply (a1,a2,a3,a4,a5,a6) (b1,b2,b3,b4,b5,b6) a b where

  ttraverse f (x,y,z,w,u,v) = (,,,,,) <$> f x <*> f y <*> f z <*> f w <*> f u <*> f v
{-#语言多段类型类,函数依赖性}
{-#语言灵活实例}
{-#语言不可判定实例}
{-#语言范围类型变量#-}
{-#语言类型族{-}
模块Tuplish在哪里
导入Data.Functor.Identity(Identity(..)
导入Data.Profunctor.Unsafe((#.),(#))
类Tuply stab | s->a,t->b,sb->t,ta->s where
ttraverse::Applicative f=>(a->f b)->s->f t
图元组::图元组STAB=>(a->b)->(s->t)
mapTuple=(runIdentity。)#。ttraverse.#(标识)
实例(a1~a、a2~a、b1~b、b2~b)
=>Tuply(a1,a2)(b1,b2)a b其中
t行程f(x,y)=(,)f x y
实例(a1~a、a2~a、a3~a、b1~b、b2~b、b3~b)
=>元组(a1、a2、a3)(b1、b2、b3)a b其中
t行程f(x,y,z)=(,)f x y z
实例(a1~a、a2~a、a3~a、a4~a、b1~b、b2~b、b3~b、b4~b)
=>元组(a1、a2、a3、a4)(b1、b2、b3、b4)a其中
t行程f(x,y,z,w)=(,,)f x f y f z w
实例(a1~a、a2~a、a3~a、a4~a、a5~a、,
b1~b、b2~b、b3~b、b4~b、b5~b)
=>元组(a1、a2、a3、a4、a5)(b1、b2、b3、b4、b5)a b其中
t行程f(x,y,z,w,u)=(,,,)f x f y f z w u
实例(a1~a、a2~a、a3~a、a4~a、a5~a、a6~a、,
b1~b、b2~b、b3~b、b4~b、b5~b、b6~b)
=>元组(a1、a2、a3、a4、a5、a6)(b1、b2、b3、b4、b5、b6)a其中
t行程f(x,y,z,w,u,v)=(,,,,)fxfyzfv
“Odd!”-它实际上是唯一可能的实现,但是元组类型的语法在某种程度上隐藏了它。更直接的是:
数据元组ab=Tuple ab
<代码>实例函子(元组a)
。。。因此,元组上
fmap
的具体类型签名是(为了清晰起见,使用冗余参数):
fmap::(b->c)->(Tuple a)b->(Tuple a)c
,其中
Tuple a
是您的
f
。我将验证这个“最后一个类型参数”业务在我第一次遇到它时确实非常奇怪。Haskell对参数的顺序有点敏感,尤其是类型参数,这与其他基本上不重要的语言有很大不同,仅供参考