泛化 ($) 如 Control.Category 泛化 (.)
Generalising ($) like Control.Category generalises (.)
我想像 Control.Category
概括 (.)
那样概括 ($)
,并且我已经使用 post 末尾的代码实现了这一点(also ideone).
在这段代码中,我创建了一个名为 FunctionObject
的 class。这个 class 有一个函数 ($)
,签名如下:
($) :: f a b -> a -> b
自然地,我将 (->)
作为此 class 的一个实例,因此 $
可以继续使用普通函数。
但这允许您创建特殊函数,例如,知道它们自己的逆函数,如下例所示。
我得出的结论是三种可能性之一:
- 我是第一个想到的
- 其他人已经做到了,我正在重新发明轮子。
- 这是个坏主意。
选项 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
在Haskell中有两种抽象用于类似的事情,一种使用Arrow
s,另一种使用Applicative
s。两者都可以分解成比 base
.
中使用的更小的部分
如果您朝 Arrow
方向和 break down the capabilities of Arrow
s into component pieces 方向前进,您将有一个单独的 class 用于那些能够将任意函数提升到箭头中的箭头。
class ArrowArr a where
arr :: (b -> c) -> a b c
这与 ArrowArr
箭头相反,其中任意箭头都可以放置到函数中。
class ArrowFun a where
($) :: a b c -> (b -> c)
如果您只是将 arr
从 Arrow
中拆分出来,您将剩下 arrow like categories that can construct and deconstruct tuples。
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
方向走,这是一个 Copointed
"Applicative
without pure
" (which goes by the name Apply
)。
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
表示根据一组特定规则构造的值(包括函数值)。
$
将态射应用于 值 。值的概念看似微不足道,但实际上,一般类别不需要有这样的概念。态射是值(箭头值......随便什么),但对象(类型)实际上不需要包含任何元素。
然而,在许多类别中,有一个特殊的对象,terminal object. In Hask, this is the ()
type. You'll notice that functions () -> a
are basically equivalent to a
values themselves. Categories in which this works are called 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
)。但是有很多类别可以构成一个好的 WellPointed
实例,如果它们完全可以在 Haskell 中正确实现的话。基本上,所有具有特定属性的数学函数类别 (LinK, Grp, {{•}, Top}...). The reason these aren't directly expressible as a Category
is that they can't have any Haskell type as an object; newer category libraries like categories or constrained-categories do allow this. For instance, 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 描述的那样。
我想像 Control.Category
概括 (.)
那样概括 ($)
,并且我已经使用 post 末尾的代码实现了这一点(also ideone).
在这段代码中,我创建了一个名为 FunctionObject
的 class。这个 class 有一个函数 ($)
,签名如下:
($) :: f a b -> a -> b
自然地,我将 (->)
作为此 class 的一个实例,因此 $
可以继续使用普通函数。
但这允许您创建特殊函数,例如,知道它们自己的逆函数,如下例所示。
我得出的结论是三种可能性之一:
- 我是第一个想到的
- 其他人已经做到了,我正在重新发明轮子。
- 这是个坏主意。
选项 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
在Haskell中有两种抽象用于类似的事情,一种使用Arrow
s,另一种使用Applicative
s。两者都可以分解成比 base
.
如果您朝 Arrow
方向和 break down the capabilities of Arrow
s into component pieces 方向前进,您将有一个单独的 class 用于那些能够将任意函数提升到箭头中的箭头。
class ArrowArr a where
arr :: (b -> c) -> a b c
这与 ArrowArr
箭头相反,其中任意箭头都可以放置到函数中。
class ArrowFun a where
($) :: a b c -> (b -> c)
如果您只是将 arr
从 Arrow
中拆分出来,您将剩下 arrow like categories that can construct and deconstruct tuples。
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
方向走,这是一个 Copointed
"Applicative
without pure
" (which goes by the name Apply
)。
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
表示根据一组特定规则构造的值(包括函数值)。
$
将态射应用于 值 。值的概念看似微不足道,但实际上,一般类别不需要有这样的概念。态射是值(箭头值......随便什么),但对象(类型)实际上不需要包含任何元素。
然而,在许多类别中,有一个特殊的对象,terminal object. In Hask, this is the ()
type. You'll notice that functions () -> a
are basically equivalent to a
values themselves. Categories in which this works are called 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
)。但是有很多类别可以构成一个好的 WellPointed
实例,如果它们完全可以在 Haskell 中正确实现的话。基本上,所有具有特定属性的数学函数类别 (LinK, Grp, {{•}, Top}...). The reason these aren't directly expressible as a Category
is that they can't have any Haskell type as an object; newer category libraries like categories or constrained-categories do allow this. For instance, 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 描述的那样。