У меня есть общее состояние, которое по сути состоит из трех кортежей, и несколько функций, каждая из которых связана с частями этого состояния. Я пытаюсь разработать набор универсальных адаптеров для таких функций, чтобы я мог использовать их в конвейере монады состояний.
Возможно, это совершенно неправильно; не стесняйтесь делать это дело.
Заранее прошу прощения за смесь Java и pidgin Scala. На самом деле я делаю это на Java в качестве учебного упражнения, но никто не успевает все это прочитать. Я исключил много неинтересных сложностей ради обсуждения; не беспокойтесь о моделировании предметной области.
Состояние, о котором идет речь, таково:
ImportState(row:CsvRow, contact:Contact, result:ImportResult)
ImportResult
является одним из ADD
, MERGE
или REJECT
.
Я определил следующие функции:
def rowToContact: ImportRow => Contact
def findMergeCandidates: Contact => (Contact, List[Contact])
// merges, or declines to merge, setting the result
def merge: (Contact, List[Contact]) => (Contact, ImportResult)
def persist: Contact => ImportResult
def commitOrRollback: ImportState => ImportState
def notifyListener: ImportState => Nothing
Адаптеры, которые я определил, довольно просты и имеют индивидуальные свойства ImportState
:
def getRow: ImportState => ImportRow
def getContact: ImportState => Contact
def setRow(f: _ => ImportRow): ImportState => ImportState
def setContact(f: _ => Contact): ImportState => ImportState
def setResult(f: _ => ImportResult): ImportState => ImportState
(Неработающий) конвейер выглядит примерно так (в Java):
State.<ImportState>init()
.map( setRow( constant(row) ) )
.map( setContact( getRow.andThen(rowToContact) ) )
.map( getContact.andThen(findMergeCandidates).andThen(merge) ) // this is where it falls apart
.map( setResult( getContact.andThen(persist) ) )
// ... lots of further processing of the persisted contact
.map(commitOrRollback)
.map(notifyListener);
Непосредственная проблема заключается в том, что merge
возвращает кортеж (Contact, ImportResult)
, который я хотел бы применить к двум свойствам состояния (contact
и result
), сохраняя при этом третье свойство row
.
До сих пор я придумал пару подходов к адаптации слияния, которые оба отстой:
Определите некоторые функции, которые упаковывают и распаковывают кортежи, и используйте их непосредственно в конвейере. Эта опция очень шумная.
Определите одноразовый адаптер для ImportState
и merge
. Эта опция кажется сдачей.
Есть ли лучший способ?