log*_*anj 5 monads state haskell functional-programming scala
我有一个基本上是3元组的一般状态,以及许多函数,每个函数都涉及该状态的一部分.我正在尝试为这些函数设计一组通用适配器,以便我可以在状态monad管道中使用它们.
这可能完全是错误的; 随意做出这种情况.
我提前为Java和pidgin Scala的混合道歉.我实际上是用Java作为学习练习,但是没有人有时间阅读这些内容.为了讨论,我已经省略了许多无趣的复杂性; 不要担心域建模.
有问题的国家是这样的:
ImportState(row:CsvRow, contact:Contact, result:ImportResult)
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
到目前为止我定义的适配器非常简单,并处理以下各项属性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
Run Code Online (Sandbox Code Playgroud)
(破碎的)管道看起来像这样(在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);
Run Code Online (Sandbox Code Playgroud)
直接的问题是merge
返回一个元组(Contact, ImportResult)
,我想将其应用于状态(contact
和result
)的两个属性,同时保留第三个属性,row
.
到目前为止,我已经提出了两种适应合并的方法,这两种方法都很糟糕:
定义一些打包和解包元组的函数,并直接在管道中使用它们.这个选项非常嘈杂.
为ImportState
和定义一次性适配器merge
.这个选项感觉就像放弃了.
有没有更好的办法?
你的问题被标记为Haskell - 我希望这意味着你可以阅读Haskell,而不是有人看到'monads'并添加它.根据这个假设,我将在这个答案中讲Haskell,因为它是我现在认为的语言;)
有一个称为"功能镜头"的有用概念,带有几个Haskell库实现.核心思想是"镜头"是一对功能:
data Lens a b = Lens { extract :: (a -> b), update :: (a -> b -> a) }
Run Code Online (Sandbox Code Playgroud)
这代表了获取和更新结构"部件"的功能性方法.使用这样的类型,您可以编写如下函数:
subState :: Lens a b -> State a t -> State b t
subState lens st = do
outer <- get
let (inner, result) = runState st (extract lens outer)
put (update lens outer inner)
return result
Run Code Online (Sandbox Code Playgroud)
将其翻译成Java听起来像一个有趣(可能非常具有挑战性)的练习!
归档时间: |
|
查看次数: |
734 次 |
最近记录: |