Bir "operasyonel monad" yaklaşımı Haskell I özünü açıklayan için daha iyi olduğunu düşünüyorum: derleyici o iletişim kurmak için, statik şeyler yapmak ve yöntem düzeyinde tipi parametrelerin devreye soktuk gerekiyor /O. Haskell versiyonu oldukça basit olabilir:
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
değerleri bazı büyülü dünya geçen fonksiyonlar değildir; Onlar sadece düz bir veri.
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
Aslında kimin IO
tip bir Haskell derleyicisi yazmak mümkün olacağını kimin çalıştırma sistemi bu değerlerini yorumladığı MyIO
çok benziyor ve: Biz bunu arzu aslında eylem temsil gerçekleştirmek için verileri yorumlayabilir doğrudan yazın.
Aşağıdaki Java'ya bir çeviri girişiminde bulundum. Hiç bir zaman bir Java programcısı olmadım ve hiç kullanılmadığımdan çok uzun zaman geçti, bu yüzden bu çok tekdüze veya hatta yanlış olabilir. Bind
ve Pure
(Control.Monad.Operational
gibi genel bir şeyin alemine getirilmesi), PrimOp
IO
alt sınıfı için run
yöntemini kullanırken, "ziyaretçi kalıbı" nın bazı sürümlerini kullanmak istediğinizi tahmin ediyorum. Gerçekten doğru Java yolunu bilmediğimden, bunu basit tutmaya çalıştım.
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;
}
}
zor biraz varoluş ölçümü ihtiyacı Bind
vardır. Java'da bunu yapmak için deyimsel yolu bilmiyorum, bu yüzden işe yaramış gibi görünen garip bir şey yaptım. Yani, iki tip değişkenini ve sınıfını bir OpenBind
bu değişkenlerden birini siler bırakan bir sınıf OpenBind
yazdı.
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());
}
}
}
primops kendilerini oldukça basit (ben çok yazdım ()
bir Java eşdeğer bulamadı benim kendi 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 "";
}
}
Ben hedef bununla ne tam olarak emin değilim ama bence siz 'Dünya'nın amacını karıştırıyorsunuz ve bu' IO 'monadını düşünmenin en iyi yolu değil.Her iki durumda da, "Dünya" tanımınız, "dönüşümlerin" girdiye ekleyebileceğini ve muhtemelen istenmeyen davranış olan çıktıdan çıkarılabileceğini ima eder. –
Amaç, java geliştiricilerine Haskell'i tanıtmaktır. Bence saf IO Haskell havalı konseptidir, bu yüzden basit bir IO modelini yapıyorum. Stdin listesinin salt okunur olmasına razıyım. –
Ben bir Java geliştiricisi değilim, ama bu kadar kıllı bir şeyin Haskell'in 'IO 'tipini tanıtmanın iyi bir yolu olabileceğini görmüyorum. Bunun için, “IO a” nın ilkel komutlar ve sürekliliklerden oluşan bir veri yapısı olarak görüldüğü bir “operasyonel monad” yaklaşımı öneririm. – dfeuer