我有一个看起来像这样的类型:
newtype Canonical Int = Canonical Int
Run Code Online (Sandbox Code Playgroud)
和一个功能
canonicalize :: Int -> Canonical Int
canonicalize = Canonical . (`mod` 10) -- or whatever
Run Code Online (Sandbox Code Playgroud)
(Canonical类型可能并不重要,它只是用于区分"原始"值和"规范化"值.)
我想创建一些机器,以便我可以规范化函数应用程序的结果.
例如:( 编辑:固定的虚假定义)
cmap :: (b->Int) -> (Canonical b) -> (Canonical Int)
cmap f (Canonical x) = canonicalize $ f x
cmap2 :: (b->c->Int) -> (Canonical b) -> (Canonical c) -> (Canonical Int)
cmap2 f (Canonical x) (Canonical y) = canonicalize $ f x y
Run Code Online (Sandbox Code Playgroud)
这表面上与Functor和Applicative类似,但它并不完全,因为它太专业了:我实际上不能编写函数(按照Functor/Applicative的同态定律的要求),除非'b'是Int.
我的目标是利用现有的,而不是写我自己的变种一样的库函数/组合程序,cmap,cmap2.那可能吗?是否有不同的类型类或构造Canonical类型的不同方式来实现我的目标?
我尝试过其他结构,比如
newtype Canonical a = Canonical { value :: a, canonicalizer :: a -> a }
Run Code Online (Sandbox Code Playgroud)
但是这会遇到同样的非可组合性问题,因为我无法将一个规范化器转换为另一个规范化器(我只想使用结果类型的规范化器,它总是Int(或Integral a)
我不能像这样强制"仅限专业化",这不是有效的Haskell:
instance (Functor Int) (Canonical Int)
Run Code Online (Sandbox Code Playgroud)
(和类似的变化)
我也试过了
newtype (Integral a) => Canonical a = Canonical a -- -XDatatypeContexts
instance (Integral a) => Functor Canonical where
fmap f (Canonical x) = canonicalize $ f x
Run Code Online (Sandbox Code Playgroud)
但GHC表示这DatatypeContexts已被弃用,这是一个坏主意,更严重的是,我得到:
`Could not deduce (Integral a1) arising from a use of 'C'
from the context (Integral a)
bound by the instance declaration
[...] fmap :: (a1 -> b) -> (C a1 -> C b)
Run Code Online (Sandbox Code Playgroud)
我认为这是说,约束Integral a实际上不能用于约束fmap到(Integral -> Integral)我希望的方式,这是有点明显的(因为fmap有两个类型变量):-(
当然,这也不是有效的Haskell
instance (Integer a) => Functor Canonical where
Run Code Online (Sandbox Code Playgroud)
是否有类似的类型类我可以使用,或者我是否错误地试图使用类型类的"隐式规范化函数调用的结果"的功能?