我试图在java中编写一些函子,monad和applicatives。我发现了一些,并选择了下面的一个。
在类别理论方面,什么是get()返回?
单位()似乎是某种身份,但从什么到什么?或许这是一个构造函数?
我看到了一个带有get()的仿函数定义。这会回来什么?
abstract class Functor6<F,T> {
protected abstract <U> Function<? extends Functor6<F,T>,? extends Functor6<?,U>> fmap(Function<T,U> f);
}
abstract class Applicative<F,T>extends Functor6<F,T> {
public abstract <U> U get(); // what is this in terms of category theory?
protected abstract <U> Applicative<?,U> unit(U value); // what is this in terms of category theory?
protected final <U> Function<Applicative<F,T>,Applicative<?,U>> apply(final Applicative<Function<T,U>,U> ff) {
return new Function<Applicative<F,T>,Applicative<?,U>>() {
public Applicative<?,U> apply(Applicative<F,T> ft) {
Function<T,U> f=ff.get();
T t=ft.get();
return unit(f.apply(t));
}
};
}
}
一些Haskell可能会有所帮助。首先,一个仿函数:
class Functor f where
fmap :: (a -> b) -> f a -> f b
我们可以读到这一点,如果一个类型f
是Functor
那么必须有一个fmap
函数,它采用类型a -> b
的函数和值oif类型f a
来产生f b
。即该类型允许将函数应用于其中的值。
Java不支持更高级的类型,如上所述定义仿函数类型是必需的,所以我们必须近似它:
interface Functor6<F, T> {
<U> Function<? extends Functor6<F, T>, ? extends Functor6<?, U>> fmap(Function<T, U> f);
}
这里泛型类型参数F
是Functor类型,相当于Haskell定义中的f
,而T
是包含的类型(如U
),相当于Haskell定义中的a
(和b
)。在没有HKT的情况下,我们必须使用通配符来指代仿函数类型(? extends Functor6<F, T>
)。
接下来,申请人:
class (Functor f) => Applicative f where
pure :: a -> f a
<*> :: f (a -> b) -> f a -> f b
即,对于类型f
是一个应用程序它必须是一个仿函数,有一个pure
操作,将值提升到适用的f
,以及一个应用操作(<*>
),在a -> b
和f
内给出一个函数(a
)在f
内,可以将函数应用于值,以在b
内产生f
。
这是您的Java等价物,使用一些Java 8功能进行了简化,并修正了一些类型:
interface Applicative<F, T> extends Functor6<F, T> {
T get();
<F, U> Applicative<F, U> unit(U value);
default <U> Function<Applicative<F, T>, Applicative<F, U>> apply(Applicative<?, Function<T, U>> ff) {
return ft -> {
Function<T, U> f = ff.get();
T t = ft.get();
return unit(f.apply(t));
};
}
}
如果我们逐行采取它:
interface Applicative<F, T> extends Functor6<F, T> {
申请人说是一个玩家。这个:
T get();
似乎是一种获取应用程序中的值的方法。这可能适用于特定情况,但一般不起作用。这个:
<F, U> Applicative<F, U> unit(U value);
应该等同于Haskell定义中的pure
函数。它应该是静态的,否则你需要一个应用值才能调用它,但是使它静态会阻止它在实际的应用实现中被覆盖。在Java中没有简单的方法来解决这个问题。
然后你有apply
方法,其权利应该等同于Haskell中的<*>
。我们可以看到它只是从应用程序中获取函数f
然后它的参数,并返回一个包含将函数应用于参数的结果的applicative。
这是车轮真正脱落的地方。应用程序如何将函数应用于值的详细信息对于每个应用程序都是特定的,并且不能像这样概括。
简而言之,这种方法是错误的。这并不是说你不能用Java实现applicative functor - 你可以而且它很容易,但你不能做的就是在语言中说明它们是应用程序,就像你在Haskell中所做的那样(使用类型类)。