Haskell 函子/类似应用程序的类型类,用于编写(a->;a)函数而不是(a->;b)?
我有这样一种类型:Haskell 函子/类似应用程序的类型类,用于编写(a->;a)函数而不是(a->;b)?,haskell,Haskell,我有这样一种类型: newtype Canonical Int = Canonical Int 和一个函数 canonicalize :: Int -> Canonical Int canonicalize = Canonical . (`mod` 10) -- or whatever (规范化类型可能并不重要,它只是用来区分“原始”值和“规范化”值。) 我想创建一些机制,以便规范化函数应用程序的结果 例如:(编辑:修复虚假定义) 这在表面上类似于函子和Applicative,
newtype Canonical Int = Canonical Int
和一个函数
canonicalize :: Int -> Canonical Int
canonicalize = Canonical . (`mod` 10) -- or whatever
(规范化类型可能并不重要,它只是用来区分“原始”值和“规范化”值。)
我想创建一些机制,以便规范化函数应用程序的结果
例如:(编辑:修复虚假定义)
这在表面上类似于函子和Applicative,但并不完全一样,因为它太专业化了:除非“b”是Int,否则我实际上无法编写函数(按照函子/Applicative同态定律的要求)
我的目标是使用现有的库函数/组合函数,而不是编写自己的变体,如cmap
,cmap2
。可能吗?是否有一种不同的类型类,或者一种不同的方法来构造规范类型,以实现我的目标
我试过其他结构,比如
newtype Canonical a = Canonical { value :: a, canonicalizer :: a -> a }
但这也会遇到同样的不可组合性问题,因为我无法将一个规范化程序转换为另一个规范化程序(我只想使用结果类型的规范化程序,它总是Int
(或Integral a
)
我不能强制“只专业化”这样,这是无效的Haskell:
instance (Functor Int) (Canonical Int)
(和类似的变化)
我也试过了
newtype (Integral a) => Canonical a = Canonical a -- -XDatatypeContexts
instance (Integral a) => Functor Canonical where
fmap f (Canonical x) = canonicalize $ f x
但是GHC说,DatatypeContexts
不受欢迎,这是一个坏主意,而且更严重,
我得到:
我想这是说约束Integral a
实际上不能用于约束fmap
到(Integral->Integral)
我希望的方式,这有点明显(因为fmap
有两个类型变量):-(
当然这也不是有效的Haskell
instance (Integer a) => Functor Canonical where
我是否可以使用类似的typeclass,或者我尝试使用typeclass来实现“隐式规范化函数调用结果”的功能是错误的?从您的类型签名来看,这看起来有点像
标识
monad
newtype Identity a = Identity a
instance Monad Identity where
return x = Identity x
f >>= (Identity x) = Identity (f x)
然后在您的示例中,canonicalize=return
和cmap f x=f>>=(return x)
希望这是有帮助的
编辑
我想到的另一个结构是自同构(我学过数学)
所以如果你有
data Automorphisms a = AMorph (a -> a)
然后你可以得到一个幺半群
instance Monoid Automorphism where
mempty = id
mappend = (.)
mconcat = foldr1 (.)
(我希望foldr1是正确的)您的
cmap
实际上可以通过fmap
实现。一开始有点奇怪,但是(>)
本身只是一个数据类型,实际上相当于阅读器
。我们可以fmap
查看返回结果
cmap :: (a -> Int) -> a -> (Canonical Int)
cmap = fmap Can
您可以使用相同的模式创建其他cmap
变体
cmap2 :: (a -> b -> Int) -> a -> b -> (Canonical Int)
cmap2 = fmap (fmap Can)
cmap3 :: (a -> b -> c -> Int) -> a -> b -> c -> (Canonical Int)
cmap3 = fmap (fmap (fmap Can))
现在在代码中看到这通常有点奇怪,在(>)
显然,这在高阶组合子中有点荒谬。无点样式可能不是最佳选择。我认为您试图实现的功能在包中可用,在本例中是单函子类型类。让我们后退一步。您确定类型签名
cmap2::(b->c->Int)->(规范Int)->(Canonical Int)
描述您想要什么?因为它看起来毫无意义。它也与函子
无关。下面是一个有效函子签名的示例:(Int->Int)->Canonical Int->Canonical Int
。我的错误是,我在将更复杂的类型简化为需要询问的内容时犯了错误。我(尝试过)改进定义,进行编辑。我同意它看起来有点像Identity
,但如果我尝试将canonicalize
放在定义的左侧,我认为同样的类型检查问题也适用。Identity
和Canonical
是参数多态的,但是canonicalize
是特殊的polymo你能解释一下吗?我想我现在太聪明了(这种特殊的多态性让我的脑袋发麻)-也许明天我会想,我的意思是,Identity
适用于任何类型的a->a
,但是canonicalize
被实现为Int->Int
你的自同构是数据的Endo
。Monoid
@misterbee:那就把Identity
用于所有东西,而只使用canonicalizi呢必要时使用ng?那么您可以在大多数情况下使用Haskell的所有多态性,并且您只需要在绝对必要时使用规范化的Int
。如果您另外定义了Identity Int
和Canonical Int
之间的同构,这种方法可能非常轻量级。这看起来令人鼓舞,但是请注意,我并不是简单地尝试用Canonical
构造函数标记一个值。我还尝试添加一个转换:canonicalize=Canonical。(`mod`10)
Ah,mono traversable的神奇之处在于它使用了“类型族”。这样,一个具体的类型Text
可以被视为Foo Char
。有趣的是,在omap
中,Char
被用作元素Text
,签名是(元素m->元素m)->m->m
这不完全是(a->a->ma->ma
。从某种意义上说,m
被视为UnElement(Element m)
,要使类型签名匹配fmap
。需要将mono遍历到fpcomplete;-)。它在不稳定的包集中可用。在我们创建9月份稳定的快照时,mono traversable不够稳定。啊,昨天我找不到汉堡包菜单来访问FPComplete IDE中的设置。切换到不稳定工作非常好!
cmap :: (a -> Int) -> a -> (Canonical Int)
cmap = fmap Can
cmap2 :: (a -> b -> Int) -> a -> b -> (Canonical Int)
cmap2 = fmap (fmap Can)
cmap3 :: (a -> b -> c -> Int) -> a -> b -> c -> (Canonical Int)
cmap3 = fmap (fmap (fmap Can))
instance Functor (r ->) where
fmap = (.)
cmap :: (a -> Int) -> a -> (Canonical Int)
cmap = (.) Can
cmap f = Can . f
cmap2 :: (a -> b -> Int) -> a -> b -> (Canonical Int)
cmap2 = (.) ((.) Can)
cmap2 = (.) (Can .)
cmap2 f = (Can .) . f
cmap3 :: (a -> b -> c -> Int) -> a -> b -> c -> (Canonical Int)
cmap3 = (.) ((.) ((.) Can))
cmap3 = (.) ((.) (Can .))
cmap3 = (.) ((Can .) .)
cmap3 f = ((Can .) .) . f