[英]how do you implement the equality and hashCode method if the class has reference type members java?
[英]How do you implement Haskell's IO type in Java?
这是我的第一次尝试:
import java.util.function.*;
import java.util.ArrayList;
public class IO<A> {
private Function<World,Tuple<World,A>> transform;
private class World {
private ArrayList<String> stdin;
private ArrayList<String> stdout;
public World() {
this.stdin = new ArrayList<String>();
this.stdout = new ArrayList<String>();
}
}
private class Tuple<F,S> {
public F fst;
public S snd;
public Tuple(F fst, S snd) {
this.fst = fst;
this.snd = snd;
}
}
public IO(Function<World,Tuple<World,A>> transform) {
this.transform = transform;
}
public IO<A> pure(A a) {
return new IO<A>(r -> new Tuple<World,A>(r,a));
}
public <B> IO<B> bind(IO<A> io, Function<A,IO<B>> f) {
return new IO<B>(r -> {
Tuple<World,A> result = io.transform.apply(r);
IO<B> ioB = f.apply(result.snd);
return ioB.transform.apply(result.fst);
});
}
}
但是当我尝试编译它时,我收到以下错误:
IO.java:29: error: incompatible types: IO<B>.World cannot be converted to IO<A>.World
Tuple<World,A> result = io.transform.apply(r);
^
where B,A are type-variables:
B extends Object declared in method <B>bind(IO<A>,Function<A,IO<B>>)
A extends Object declared in class IO
我不明白的是世界级与类型变量没有关系,但javac认为它确实存在。 我究竟做错了什么?
撇开您在Java中复制Haskell IO类型的方法的保真度:
编译器认为, A
在你的bind
方法的签名是一样的A
类定义。 你告诉过我们这不是用语言。 为了将它传达给编译器,您需要将事物设置为静态并引入几个方法级类型参数:
import java.util.function.*;
import java.util.ArrayList;
public class IO<A> {
private Function<World,Tuple<World,A>> transform;
private static class World {
private ArrayList<String> stdin;
private ArrayList<String> stdout;
public World() {
this.stdin = new ArrayList<String>();
this.stdout = new ArrayList<String>();
}
}
private static class Tuple<F,S> {
public F fst;
public S snd;
public Tuple(F fst, S snd) {
this.fst = fst;
this.snd = snd;
}
}
private IO(Function<World,Tuple<World,A>> transform) {
this.transform = transform;
}
public static <A> IO<A> pure(A a) {
return new IO<A>(r -> new Tuple<World,A>(r,a));
}
public static <A,B> IO<B> bind(IO<A> io, Function<A,IO<B>> f) {
return new IO<B>(r -> {
Tuple<World,A> result = io.transform.apply(r);
IO<B> ioB = f.apply(result.snd);
return ioB.transform.apply(result.fst);
});
}
}
我认为“操作monad”方法更适合解释Haskell I / O的本质。 Haskell版本可以非常简单:
data PrimOp a where
PutStr :: String -> PrimOp ()
GetLine :: PrimOp String
-- Whatever other primitives you want
data MyIO a where
Pure :: a -> MyIO a
Bind :: !(MyIO a) -> (a -> MyIO b) -> MyIO b
LiftPrim :: !(PrimOp a) -> MyIO a
instance Functor MyIO where
fmap = liftM
instance Applicative MyIO where
pure = Pure
(<*>) = ap
instance Monad MyIO where
(>>=) = Bind
MyIO
价值观不是一些神奇的世界传递函数; 他们只是简单的数据。 如果我们愿意,我们可以解释数据以实际执行所表示的操作:
runPrimOp :: PrimOp a -> IO a
runPrimOp (PutStr s) = putStr s
runPrimOp GetLine = getLine
runMyIO :: MyIO a -> IO a
runMyIO (Pure a) = pure a
runMyIO (Bind m f) = runMyIO m >>= runMyIO . f
runMyIO (LiftPrim prim) = runPrimOp prim
实际上可以编写一个Haskell编译器,其IO
类型看起来很像MyIO
,并且其运行时系统直接解释该类型的值。
我试过下面的Java翻译。 我从来没有真正成为一名Java程序员,自从我使用它以来已经有很长一段时间了,所以这可能是非常单一的,甚至是错误的。 我想你可能想要使用某种版本的“访问者模式”来表示Bind
和Pure
解释(将事物带入像Control.Monad.Operational
这样的通用领域),同时为PrimOp
子类使用run
方法IO
。 因为我真的不知道正确的Java方式,所以我试图保持简单。
public interface IO <A> {
public A run ();
}
public final class Pure <A> implements IO <A> {
private final A val;
Pure (A x) { val = x; }
public A run () {
return val;
}
}
棘手的一点是Bind
,它需要存在量化。 我不知道在Java中这样做的惯用方法,所以我做了一些似乎有用的尴尬。 也就是说,我编写了一个辅助类OpenBind
,它暴露了两个类型变量,然后是一个包含OpenBind
的类Bind
,其中一个变量是狂野的。
import java.util.function.Function;
public final class Bind <A> implements IO <A> {
private final OpenBind <?,A> ob;
public <B> Bind (IO <B> m, Function <B,IO <A>> f) {
ob = new OpenBind <B,A> (m, f);
}
public A run() {
return (ob.run());
}
private final static class OpenBind <Fst,Snd> {
private final IO <Fst> start;
private final Function <Fst, IO <Snd>> cont;
public OpenBind (IO <Fst> m, Function <Fst, IO <Snd>> f) {
start = m;
cont = f;
}
public final Snd run () {
Fst x = start.run();
IO <Snd> c = cont.apply(x);
return (c.run());
}
}
}
初学者本身很简单(我找不到Java的等价物()
所以我写了自己的Unit
):
public class PutStr implements IO <Unit> {
private String str;
public PutStr (String s) {
str = s;
}
public Unit run () {
System.out.print(str);
return Unit.unit;
}
}
public final class Unit {
private Unit () {}
public static final Unit unit = new Unit ();
}
public class GetLine implements IO <String> {
private GetLine () {}
public static final GetLine getLine = new GetLine ();
public String run () {
// Replace the next line with whatever you actually use to
// read a string.
return "";
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.