![](/img/trans.png)
[英]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.