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 在newtype中映射值_Haskell_Newtype - Fatal编程技术网

Haskell 在newtype中映射值

Haskell 在newtype中映射值,haskell,newtype,Haskell,Newtype,假设定义了以下newtype: newtype A a = A a 还有一个功能: f :: A a -> A a (<$$>) :: k a -> k b -> h (k a) -> h (k b) {-# LANGUAGE DeriveGeneric #-} import Control.Newtype (Newtype, over) import GHC.Generics newtype A a = A a newtype B a = B (A

假设定义了以下
newtype

newtype A a = A a
还有一个功能:

f :: A a -> A a
(<$$>) :: k a -> k b -> h (k a) -> h (k b)
{-# LANGUAGE DeriveGeneric #-}
import Control.Newtype (Newtype, over)
import GHC.Generics

newtype A a = A a

newtype B a = B (A a) deriving (Generic)

instance Newtype (B a)

f :: A a -> A a
f = undefined

fb :: B a -> B a
fb = over B f
现在假设我定义了另一个
newtype
,它包含
A

newtype B a = B (A a)
然后我想定义一个函数
fb
,它在
ba
上运行,但只使用
f

fb :: B a -> B a
fb (B x) = B (f x)
现在这很不方便,因为我必须在类型为
ba
的元素中展开并包装值。如果我只需要定义一个这样的
fb
,这就不会那么糟糕了,但是如果有很多这样的函数,这就变得相当乏味了

如果有一个带有函数的类型类,我会很高兴:

f :: A a -> A a
(<$$>) :: k a -> k b -> h (k a) -> h (k b)
{-# LANGUAGE DeriveGeneric #-}
import Control.Newtype (Newtype, over)
import GHC.Generics

newtype A a = A a

newtype B a = B (A a) deriving (Generic)

instance Newtype (B a)

f :: A a -> A a
f = undefined

fb :: B a -> B a
fb = over B f

可能这样的抽象已经存在,但我找不到它。

实际上使用
newtype
的主要原因之一是为一个新类型派生新类型类实例,该新类型被包装在现有类型上

所以这很简单。您只需要为Functor类编写一个实例,就这样

newtype Team a = Team a deriving (Show , Eq)

instance Functor Team where
  fmap f (Team x) = Team (f x)

newtype League a = League (Team a) deriving (Show , Eq)

instance Functor League where
  fmap f (League x) = League (fmap f x)


upgradeTeam :: (Int -> Int) -> Team [Int] -> Team [Int]
upgradeTeam f = fmap (map f)

upgradeLeague :: (Int -> Int) -> League [Int] -> League [Int]
upgradeLeague f = fmap (map f) 

prependToLeague :: League [Int] -> Int -> League [Int]
prependToLeague x n = fmap (n:) x

*Main> upgradeTeam (+1) (Team [0,1,2,3])
Team [1,2,3,4]

*Main> upgradeLeague (*2) (League (Team [1,2,3,4]))
League (Team [2,4,6,8])

*Main> prependToLeague (League (Team [2,4,6,8])) 42
League (Team [42,2,4,6,8])

一种解决方案是使用软件包,尤其是功能:

f :: A a -> A a
(<$$>) :: k a -> k b -> h (k a) -> h (k b)
{-# LANGUAGE DeriveGeneric #-}
import Control.Newtype (Newtype, over)
import GHC.Generics

newtype A a = A a

newtype B a = B (A a) deriving (Generic)

instance Newtype (B a)

f :: A a -> A a
f = undefined

fb :: B a -> B a
fb = over B f

请注意,
over
需要外部的
B
构造函数作为参数,而不仅仅是函数
f

如果您喜欢danidiaz的答案,您可能会喜欢这个更“现代”的
over

mover :: (Coercible o n, Coercible o' n')
      => (o -> n)
      -> (o' -> n')
      -> (o -> o') -> n -> n'
mover _pack _pack' = coerce

这跳过了所有的实例,而支持更显式的传递。

对于新类型的特殊情况,您应该只使用
Data.concure
,它提供了
concure::(a->a)->a->a和
concure:(a->a)->ba->ba和
concure(a->a)->B a->B a
。我认为这是自动包装/展开的方法。@user2407038,确实如此,但这不一定要在使用站点上。对于一个新类型,
实例函子N,其中fmap=concure
非常合理。我看不出你建议的类型类会有什么帮助。类型
ba->ba
h(ka)->h(kb)
不统一,这让人想起newtype/newtype泛型包中的
over
。但是,
over
需要外部newtype构造函数作为附加参数。我更可能接触到
Control.Lens.Iso.compressed
以及
Control.Lens.Setter.over
。它们不需要
Newtype
Generic
实例。实际上,您可以更简单地完成这项工作。请看我将要写的答案。这在我的情况下不起作用,因为
fmap::(a->b)->fa->fb
。我想要重用的函数的类型是
aaa->ab
,因此我需要类似
?::(A->A b)->b A->b A
。请注意,我不是在
a
类型的元素上操作(在您的示例中),而是在
Team a
类型的元素上操作。对于我正在处理的问题
A A=Map A Integer
,所以这个例子不起作用。另一个答案中的函数
over
。@Damian Nadales
A->AB
实际上是
fmap g
A
类型上的部分应用,其中
g
是类型
(A->b)
所以
:t fmap g
会给你
(f A->f b)
其中
f
表示函子
A
。然后,您只需应用另一个
fmap
,但这次是在类型
B
上,如
fmap(fmap g)
或“fmap”。fmap$g`这实际上是在上述代码中键入的
联盟的函子实例中发生的情况。如果你喜欢联盟的函子实例(你的B类型)直接在
(A A->A B)
上操作,而不是
(A->B)
,那么让联盟的函子实例像
fmap f(League x)=League(f x)
一样。在哪里定义了
\u pack
?此外,我还希望在某些库中已经定义了
mover
,这些只是通配符。您可以编写
mover\uuu=强制