我曾考虑将($)
概括为Control.Category
一般性(.)
,并且我已使用此帖末尾的代码(also ideone )。
在此代码中,我创建了一个名为FunctionObject
的类。此类具有带有以下签名的函数($)
:
($) :: f a b -> a -> b
当然,我将(->)
作为此类的一个实例,以便$
继续使用普通函数。
但是这允许你创建特殊的函数,例如,知道它们自己的逆函数,如下例所示。
我已经得出结论有三种可能性之一:
选项1似乎不太可能,我在hayoo上的搜索没有显示选项2,所以我怀疑选项3最有可能,但是如果有人能够解释为什么会这样做会很好。
import Prelude hiding ((.), ($))
import Control.Category ((.), Category)
class FunctionObject f where
($) :: f a b -> a -> b
infixr 0 $
instance FunctionObject (->) where
f $ x = f x
data InvertibleFunction a b =
InvertibleFunction (a -> b) (b -> a)
instance Category InvertibleFunction where
(InvertibleFunction f f') . (InvertibleFunction g g') =
InvertibleFunction (f . g) (g' . f')
instance FunctionObject InvertibleFunction where
(InvertibleFunction f _) $ x = f $ x
inverse (InvertibleFunction f f') = InvertibleFunction f' f
add :: (Num n) => n -> InvertibleFunction n n
add n = InvertibleFunction (+n) (subtract n)
main = do
print $ add 2 $ 5 -- 7
print $ inverse (add 2) $ 5 -- 3
答案 0 :(得分:9)
$
将态射应用于值。价值的概念似乎微不足道,但实际上,一般类别不需要这样的概念。态射是值(箭头值......等等),但对象(类型)实际上不需要包含任何元素。
但是,在许多类别中,都有一个特殊对象terminal object。在 Hask 中,这是()
类型。您会注意到函数() -> a
基本上等同于a
值本身。其中有效的类别称为well-pointed。实际上,$
之类的基本要素是
class Category c => WellPointed c where
type Terminal c :: *
point :: a -> Terminal c `c` a
unpoint :: Terminal c `c` a -> a
然后您可以通过
定义应用程序运算符($) :: WellPointed c => c a b -> a -> b
f $ p = unpoint $ f . point p
WellPointed
的明显例子当然是 Hask 本身:
instance WellPointed (->) where
type Terminal c = ()
--point :: a -> () -> a
point a () = a
--unpoint :: (() -> a) -> a
unpoint f = f ()
另一个众所周知的类别Kleisli
,不是我编写的WellPointed
实例(它允许point
,但不允许unpoint
1}})。但是如果它们可以在Haskell中正确实现,那么有很多类别可以构成一个好的WellPointed
实例。基本上,具有特定属性的所有数学函数类别(LinK,Grp,{{•}, Top} ...)。这些不能直接表达为Category
的原因是它们不能将任何Haskell类型作为对象;较新的类别库(例如categories或constrained-categories)允许这样做。例如,I have implemented this:
instance (MetricScalar s) => WellPointed (Differentiable s) where
unit = Tagged Origin
globalElement x = Differentiable $ \Origin -> (x, zeroV, const zeroV)
const x = Differentiable $ \_ -> (x, zeroV, const zeroV)
如您所见,the class interface实际上与我上面写的有点不同。在Haskell中没有一种普遍接受的方式来实现这样的东西......在constrained-categories
中,$
运算符实际上更像Cirdec描述的那样。
答案 1 :(得分:5)
在Haskell中有两个用于此类事物的抽象,一个使用Arrow
s和另一个Applicative
s。两者都可以分解为比base
中使用的更小的部分。
如果你进入Arrow
方向和Inspection Property,那么你可以为那些能够将任意函数提升到箭头中的箭头单独设置一个类。
class ArrowArr a where
arr :: (b -> c) -> a b c
这与ArrowArr
箭头相反,箭头可以将任意箭头拖放到函数中。
class ArrowFun a where
($) :: a b c -> (b -> c)
如果您只是将arr
与Arrow
分开,则会留下break down the capabilities of Arrow
s into component pieces。
class Category a => ArrowLike a where
fst :: a (b, d) b
snd :: a (d, b) b
(&&&) :: a b c -> a b c' -> a b (c,c')
如果你向Applicative
方向走,这是一个arrow like categories that can construct and deconstruct tuples“Applicative
没有pure
”(名称为Copointed
)。
class Copointed p where Source
copoint :: p a -> a
class Functor f => Apply f where
(<.>) :: f (a -> b) -> f a -> f b
当你这样做时,你通常会删除函数的Category
,而是有一个类型构造函数C a
来表示根据一组规则构造的值(包括函数值)。