0

私は関数型プログラミング、特に関数型 Java で遊んでいます。私は自分のバージョンの IO Monad を成功裏に実装し、自分のコア用の IO アクションを書いています。基本的に、オブジェクトを Xml ファイルにシリアル化します (オブジェクト タイプは、カスタム XmlWritable インターフェイスを拡張します)。

残念ながら、これを行うには、OutputStream のインスタンスと XmlSerializer の 1 つのインスタンスを作成する必要があります。OutputStream のスコープは XmlSerializer のスコープよりも広いため、IO モナド内で両方のライフサイクルを正しく処理できることがわかる唯一の方法は、両方をタプルに入れ、XmlSerializer を使用して記述した後に OutputStream を閉じることです。 .

これは重くて醜いコードにつながります (Java 6 は間違いなくこれに最適ではありません):

public abstract class IO<R> {
    [...]
}

public class IOActions {

    public final F<String, IO<OutputStream>> openFileFn() {
        return new F<String, IO<OutputStream>>() {
            @Override
            public IO<OutputStream> f(String fileName) {
                [...]
            }
        };
    }

    /* This will be partially applied, encoding will be fixed */
    public static final F<OutputStream, IO<P2<OutputStream, XmlSerializer>>> initSerializer() {
        return new F<OutputStream, IO<P2<OutputStream, XmlSerializer>>>() {
            @Override
            public IO<P2<OutputStream, XmlSerializer>> f(OutputStream os) {
                XmlSerializer = new ...
                [...]
            }

        };
    }

    /* This will be partially applied as well */
    public static final F2<XmlWritable, P2<OutputStream, XmlSerializer>, IO<P2<OutputStream, XmlSerializer>>> writeObjectFn() {
        return new F2<XmlWritable, P2<OutputStream, XmlSerializer>, IO<P2<OutputStream, XmlSerializer>>>() {
            @Override
            public IO<P2<OutputStream, XmlSerializer>> f(XmlWritable object, P2<OutputStream, XmlSerializer> p) {
                [...]
            }
        };
    }

関数型プログラミングでユースケースを処理するより慣用的な理由はありますか?

潜んでいると、私は状態モナドを発見しました...しかし、Functional JavaでIOモナドの上に状態モナドを適用するとどうなるかを見るのがちょっと怖いです。

4

2 に答える 2

0

これが私が思いついたものです。フィードバックをお待ちしております。リンクされたディスカッションからインスピレーションを得て、上記の回答に従いました。

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

    }
}
于 2013-12-04T19:13:46.747 に答える