Java 范围管理-有状态IO Monad?

Java 范围管理-有状态IO Monad?,java,functional-programming,functional-java,Java,Functional Programming,Functional Java,我在玩函数式编程,尤其是函数式Java。我已经成功地实现了我的IO Monad版本,我正在为我的核心编写IO操作。它基本上是将对象序列化为Xml文件(对象类型扩展了自定义XmlWritable接口) 不幸的是,为了做到这一点,需要创建OutputStream的一个实例和XmlSerializer的一个实例。OutputStream的范围比XmlSerializer的范围更广,这意味着我能看到的正确处理IO monad中的两个生命周期的唯一方法是将它们一起放在元组中,在使用XmlSerialize

我在玩函数式编程,尤其是函数式Java。我已经成功地实现了我的IO Monad版本,我正在为我的核心编写IO操作。它基本上是将对象序列化为Xml文件(对象类型扩展了自定义XmlWritable接口)

不幸的是,为了做到这一点,需要创建OutputStream的一个实例和XmlSerializer的一个实例。OutputStream的范围比XmlSerializer的范围更广,这意味着我能看到的正确处理IO monad中的两个生命周期的唯一方法是将它们一起放在元组中,在使用XmlSerializer编写之后关闭OutputStream

这导致了繁重而难看的代码(Java 6肯定不是最好的):

公共抽象类IO{
[...]
}
公共集体诉讼{
公开最终文件F openFileFn(){
返回新的F(){
@凌驾
公共IO f(字符串文件名){
[...]
}
};
}
/*这将部分应用,编码将是固定的*/
公共静态final init序列化程序(){
返回新的F(){
@凌驾
公共IO f(输出流os){
XmlSerializer=新建。。。
[...]
}
};
}
/*这也将部分适用*/
公共静态最终F2 writeObject fn(){
返回新的F2(){
@凌驾
公共IO f(XmlWritable对象,p2p){
[...]
}
};
}
在函数式编程中,为什么要处理我的用例,还有更为惯用的说法吗


潜伏着,我发现了状态Monad…但我有点害怕看到如果我在Functional Java中的IO Monad之上应用状态Monad会发生什么。

我实际上从Functional Java中获得了很大的灵感来解决类似的问题。我制作了自己的“XML组合器”(以及更多)从这个模式,所以它值得学习

你可能会发现谷歌群组很有用

编辑-回复评论:

按照代码进行操作:
请注意如何使用启动新连接,请注意,您有几个选项来启动连接,一个最终提交,另一个最终回滚。这只是两个可以在计算中“携带”的示例。本质上,您的每一次计算(普通的modaic绑定)都可能携带信息

以下是我在上述讨论中给出的一个示例:

DB<PreparedStatement> prepareStatement(final String sql) {
  return new DB<PreparedStatement>() {
     public PreparedStatement run(Connection c) throws SQLException {
        return c.prepareStatement(sql);
}}}

// for a query that a reader might perform, i might have a function like this:   
F<PreparedStatement, DB<ResultSet>> runStatement() {
   public DB<ResultSet> f(final PreparedStatement s) {
      return new DB<ResultSet>() {
        public ResultSet run (Connection c) throws SQLException {
           return s.executeQuery();
}}}

希望这有帮助!

以下是我的想法。非常感谢您的反馈。 我遵循上面的答案,从讨论中获得灵感:

public class IOXml<T extends XmlWritable> implements DataWriter<T>{

    private final XmlSerializer mXmlSerializer;
    private final Option<String> mXmlEncoding;
    private final IO<OutputStream> ioCreateStream;
    private final F<OutputStream, IO<Unit>> ioCloseStream;

    @Inject
    IOXml(IO<OutputStream> createStream, F<OutputStream, IO<Unit>> closeStream, XmlSerializer xmlSerializer, Option<String> xmlEncoding) {
        mXmlSerializer = xmlSerializer;
        mXmlEncoding = xmlEncoding;
        ioCreateStream = createStream;
        ioCloseStream = closeStream;
    }

    /**
     * Write a T object which is XmlWritable.

     * @param osAndSer The tuple containing OutputStream and XmlSerializer.
     * @param object The object to write.
     * @return IO monad object.
     */
    protected IO<Unit> writeObject(final T object) {
        return new IO<Unit>() {
            @Override
            public Unit performIO() throws IOException {
                object.writeXml(mXmlSerializer);
                return Unit.unit();
            }
        };
    }

    protected final F<Unit, IO<Unit>> writeObjectFn(final T object) {
        return new F<Unit, IO<Unit>>() {
            @Override
            public IO<Unit> f(Unit a) {
                return writeObject(object);
            }
        };
    }

    /**
     * Initialize the XmlSerializer before using it.
     * @param os An OutputStream.
     * @param encoding The encoding of the xml file.
     * @return An IO action returning nothing.
     */
    protected IO<Unit> initXml(final OutputStream os) {
        return new IO<Unit>() {
            @Override
            public Unit performIO() throws IOException {
                mXmlSerializer.setOutput(os, mXmlEncoding.toNull());
                mXmlSerializer.startDocument(mXmlEncoding.toNull(), true);
                return Unit.unit();
            }
        };
    }

    /**
     * Close the XmlSerializer after.
     * @return An IO action returning nothing.
     */
    protected IO<Unit> closeXml() {
        return new IO<Unit>() {
            @Override
            public Unit performIO() throws IOException {
                mXmlSerializer.endDocument();
                return Unit.unit();
            }
        };
    }

    protected final F<Unit, IO<Unit>> closeXmlFn() {
        return new F<Unit, IO<Unit>>() {
            @Override
            public IO<Unit> f(Unit a) {
                return closeXml();
            }
        };
    }

    @Override
    public void close() throws IOException {
        closeXml().performIO();
    }

    @Override
    public void write(T object) {
        throw new UnsupportedOperationException("Are you sure? IOXml is a functional class. Use the function returned by liftIO instead.");
    }

    /**
     * Curried function to write XML objects, given the object itself and an OutputStream.
     * @return The curried function.
     */
    protected F<OutputStream, F<T, IO<Unit>>> writeFn() {
        // returning the outer
        return new F<OutputStream, F<T, IO<Unit>>>() {
            @Override
            public F<T, IO<Unit>> f(final OutputStream os) {
                // Returning the inner
                return new F<T, IO<Unit>>() {
                    @Override
                    public IO<Unit> f(T object) {
                        return initXml(os).bind(writeObjectFn(object)).bind(closeXmlFn());
                    }
                };
            }
        };
    }

    @Override
    public IO<Unit> writeIO(final T object) {
        return IOImpl.bracket(ioCreateStream,                      // init
                       ioCloseStream,                              // close
                       Function.partialApply2(writeFn(), object)); // body

    }
}
public类IOXml实现DataWriter{
私有最终XmlSerializer mXmlSerializer;
私人最终选择权MXMLENCODE;
私有最终IO ioCreateStream;
私人最终融资;
@注入
IOXml(IO createStream、F closeStream、XmlSerializer XmlSerializer、选项xmlEncoding){
mXmlSerializer=xmlSerializer;
mXmlEncoding=xmlncoding;
ioCreateStream=createStream;
ioCloseStream=closeStream;
}
/**
*编写一个可XMLWrite的T对象。
*@param osAndSer包含OutputStream和XmlSerializer的元组。
*@param object要写入的对象。
*@return IO monad对象。
*/
受保护的IO写对象(最终T对象){
返回新IO(){
@凌驾
公共单元performIO()引发IOException{
writeXml(mXmlSerializer);
返回单位。单位();
}
};
}
受保护的最终F写对象Fn(最终T对象){
返回新的F(){
@凌驾
公共IO f(a单元){
返回writeObject(object);
}
};
}
/**
*在使用XmlSerializer之前初始化它。
*@param操作一个输出流。
*@param encoding xml文件的编码。
*@返回一个IO操作,但不返回任何内容。
*/
受保护的IO initXml(最终输出流os){
返回新IO(){
@凌驾
公共单元performIO()引发IOException{
setOutput(os,mXmlEncoding.toNull());
mXmlSerializer.startDocument(mxmlencode.toNull(),true);
返回单位。单位();
}
};
}
/**
*完成后关闭XmlSerializer。
*@返回一个IO操作,但不返回任何内容。
*/
受保护的IO closeXml(){
返回新IO(){
@凌驾
公共单元performIO()引发IOException{
mXmlSerializer.endDocument();
返回单位。单位();
}
};
}
受保护的最终F closeXmlFn(){
返回新的F(){
@凌驾
公共IO f(a单元){
返回closeXml();
}
};
}
@凌驾
public void close()引发IOException{
closeXml().performIO();
}
@凌驾
公共无效写入(T对象){
抛出新的UnsupportedOperationException(“您确定吗?IOXml是一个函数类。请改用liftIO返回的函数。”);
}
/**
*Curried函数,用于在给定对象本身和输出流的情况下编写XML对象。
*@返回curried函数。
*/
受保护的F writeFn(){
//返回外部
返回新的F(){
@凌驾
公共F(最终输出流os){
//回归内心
返回新的F(){
@凌驾
公共IO f(T对象){
返回initXml(os.bind(writeObjectFn(object)).bind(closeXmlFn());
}
};
}
};
}
@凌驾
公共IO写入(最终T对象){
返回IOImpl.bracket(ioCreateStream,
ResultSet rs = DbState.reader("conn-url").run(prepareStatement("select * from table").bind(runStatement());
public class IOXml<T extends XmlWritable> implements DataWriter<T>{

    private final XmlSerializer mXmlSerializer;
    private final Option<String> mXmlEncoding;
    private final IO<OutputStream> ioCreateStream;
    private final F<OutputStream, IO<Unit>> ioCloseStream;

    @Inject
    IOXml(IO<OutputStream> createStream, F<OutputStream, IO<Unit>> closeStream, XmlSerializer xmlSerializer, Option<String> xmlEncoding) {
        mXmlSerializer = xmlSerializer;
        mXmlEncoding = xmlEncoding;
        ioCreateStream = createStream;
        ioCloseStream = closeStream;
    }

    /**
     * Write a T object which is XmlWritable.

     * @param osAndSer The tuple containing OutputStream and XmlSerializer.
     * @param object The object to write.
     * @return IO monad object.
     */
    protected IO<Unit> writeObject(final T object) {
        return new IO<Unit>() {
            @Override
            public Unit performIO() throws IOException {
                object.writeXml(mXmlSerializer);
                return Unit.unit();
            }
        };
    }

    protected final F<Unit, IO<Unit>> writeObjectFn(final T object) {
        return new F<Unit, IO<Unit>>() {
            @Override
            public IO<Unit> f(Unit a) {
                return writeObject(object);
            }
        };
    }

    /**
     * Initialize the XmlSerializer before using it.
     * @param os An OutputStream.
     * @param encoding The encoding of the xml file.
     * @return An IO action returning nothing.
     */
    protected IO<Unit> initXml(final OutputStream os) {
        return new IO<Unit>() {
            @Override
            public Unit performIO() throws IOException {
                mXmlSerializer.setOutput(os, mXmlEncoding.toNull());
                mXmlSerializer.startDocument(mXmlEncoding.toNull(), true);
                return Unit.unit();
            }
        };
    }

    /**
     * Close the XmlSerializer after.
     * @return An IO action returning nothing.
     */
    protected IO<Unit> closeXml() {
        return new IO<Unit>() {
            @Override
            public Unit performIO() throws IOException {
                mXmlSerializer.endDocument();
                return Unit.unit();
            }
        };
    }

    protected final F<Unit, IO<Unit>> closeXmlFn() {
        return new F<Unit, IO<Unit>>() {
            @Override
            public IO<Unit> f(Unit a) {
                return closeXml();
            }
        };
    }

    @Override
    public void close() throws IOException {
        closeXml().performIO();
    }

    @Override
    public void write(T object) {
        throw new UnsupportedOperationException("Are you sure? IOXml is a functional class. Use the function returned by liftIO instead.");
    }

    /**
     * Curried function to write XML objects, given the object itself and an OutputStream.
     * @return The curried function.
     */
    protected F<OutputStream, F<T, IO<Unit>>> writeFn() {
        // returning the outer
        return new F<OutputStream, F<T, IO<Unit>>>() {
            @Override
            public F<T, IO<Unit>> f(final OutputStream os) {
                // Returning the inner
                return new F<T, IO<Unit>>() {
                    @Override
                    public IO<Unit> f(T object) {
                        return initXml(os).bind(writeObjectFn(object)).bind(closeXmlFn());
                    }
                };
            }
        };
    }

    @Override
    public IO<Unit> writeIO(final T object) {
        return IOImpl.bracket(ioCreateStream,                      // init
                       ioCloseStream,                              // close
                       Function.partialApply2(writeFn(), object)); // body

    }
}