Haskell 中是否有任何机制可以在记录类型中做同样的事情?
你可以做的是隐藏构造函数,而提供一个函数作为构造函数。
假设我们有一个要更新的列表,以及一个修订号,那么我们可以将其定义为:
data RevisionList a = RevisionList { theList :: [a],
revision :: Int }
deriving Show
现在我们可以定义一个函数,用一个初始列表初始化BuildList:
revisionList :: [a] -> RevisionList a
revisionList xs = RevisionList { theList = xs, revision=0 }
通过将构造函数隐藏在module 导出中,我们因此隐藏了用另一个版本而不是版本0 来初始化它的可能性。所以模块可能看起来像:
module Foo(RevisionList(), revisionList)
data RevisionList a = RevisionList { theList :: [a],
revision :: Int }
revisionList :: [a] -> RevisionList a
revisionList xs = RevisionList { theList = xs, revision=0 }
类似于 OOP 中的构建器模式?
例如,我们可以为此使用 State monad。例如:
module Foo(RevisionList(), revisionList,
increvision, RevisionListBuilder, prefixList)
import Control.Monad.State.Lazy
type RevisionListBuilder a = State (RevisionList a)
increvision :: RevisionListBuilder a ()
increvision = do
rl <- get
put (rl { revision = 1 + revision rl})
prefixList :: a -> RevisionListBuilder a ()
prefixList x = do
rl <- get
put (rl { theList = x : theList rl })
increvision
所以到目前为止,我们 get RevisionList 执行更新,并返回 put 新结果。
所以现在另一个模块可以导入我们的Foo,并使用如下构建器:
some_building :: RevisionListBuilder Int ()
some_building = do
prefixList 4
prefixList 1
现在我们可以在修订版2 上“制作”一个RevisionList 并作为最终列表[1,4,2,5] 使用:
import Control.Monad.State.Lazy(execState)
some_rev_list :: RevisionList Int
some_rev_list = execState some_building (revisionList [2,5])
所以看起来大概是这样的:
Foo.hs:
module Foo(RevisionList(), revisionList,
increvision, RevisionListBuilder, prefixList)
data RevisionList a = RevisionList { theList :: [a],
revision :: Int }
deriving Show
type RevisionListBuilder a = State (RevisionList a)
revisionList :: [a] -> RevisionList a
revisionList xs = RevisionList { theList = xs, revision=0 }
increvision :: RevisionListBuilder a ()
increvision = do
rl <- get
put (rl { revision = 1 + revision rl})
prefixList :: a -> RevisionListBuilder a ()
prefixList x = do
rl <- get
put (rl { theList = x : theList rl })
increvision
Bar.hs:
import Foo
import Control.Monad.State.Lazy(execState)
some_building :: RevisionListBuilder Int ()
some_building = do
prefixList 4
prefixList 1
some_rev_list :: RevisionList Int
some_rev_list = execState some_building (revisionList [2,5])
所以现在我们用some_building的“建筑”构造了一个some_rev_list:
Foo Bar> some_rev_list
RevisionList {theList = [1,4,2,5], revision = 2}