static IEnumerable<T> MakeSequence<T>(T item){yield return item;}// Extract a valuestatic T First<T>(IEnumerable<T> sequence){// let's just take the first oneforeach(T item in sequence) return item;throw new Exception("No first item");}// "Bind" is called "SelectMany"static IEnumerable<T> SelectMany<T>(IEnumerable<T> seq, Func<T, IEnumerable<T>> func){foreach(T item in seq)foreach(T result in func(item))yield return result;}
static IEnumerable<U> SelectMany<T,U>(IEnumerable<T> seq, Func<T, IEnumerable<U>> func){foreach(T item in seq)foreach(U result in func(item))yield return result;}
它被描述为“函数式编程的领先设计模式”,但示例中使用的语言是Scala,它既是面向对象的又是函数式的。 您可以在博客文章“单子-在Scala中抽象计算的另一种方法”中阅读有关Monad in Scala的更多信息,从Debasish Ghosh(2008年3月27日)开始。
类型构造函数 M如果支持以下操作,则为monad:
# the return functiondef unit[A] (x: A): M[A]
# called "bind" in Haskelldef flatMap[A,B] (m: M[A]) (f: A => M[B]): M[B]
# Other two can be written in term of the first two:
def map[A,B] (m: M[A]) (f: A => B): M[B] =flatMap(m){ x => unit(f(x)) }
def andThen[A,B] (ma: M[A]) (mb: M[B]): M[B] =flatMap(ma){ x => mb }
newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }
以便我们可以将(MaybeT m)中的操作转换为m中的操作,从而有效地折叠层。在这种情况下,runMaybeT:: MaybeT m a->m(也许a)是我们的类连接方法。(MaybeT m)是一个monad,MaybeT:: m(也许a)->MaybeT m a实际上是m中新型monad操作的构造函数。
data RandomF r a = GetRandom (r -> a) deriving Functortype Random r a = Free (RandomF r) a
type RandomT m a = Random (m a) (m a) -- model randomness in a monad by computing random monad elements.getRandom :: Random r rrunRandomIO :: Random r a -> IO a (use some kind of IO-based backend to run)runRandomIO' :: Random r a -> IO a (use some other kind of IO-based backend)runRandomList :: Random r a -> [a] (some kind of list-based backend (for pseudo-randoms))
interface IMonad<T> {static IMonad<T> create(T t); // not allowedpublic IMonad<U> flatMap<U>(Func<T, IMonad<U>> f); // not specific enough,// because the function must return the same kind of monad, not just any monad}
-- a * bmultiply :: Int -> Int -> Maybe Intmultiply a b = return (a*b)
-- divideBy 5 100 = 100 / 5divideBy :: Int -> Int -> Maybe IntdivideBy 0 _ = Nothing -- dividing by 0 gives NOTHINGdivideBy denom num = return (quot num denom) -- quotient of num / denom
-- tagged valueval1 = Just 160
-- array of functions feeded with val1array1 = val1 >>= divideBy 2 >>= multiply 3 >>= divideBy 4 >>= multiply 3
-- array of funcionts created with the do notation-- equals array1 but for the feeded val1array2 :: Int -> Maybe Intarray2 n = dov <- divideBy 2 nv <- multiply 3 vv <- divideBy 4 vv <- multiply 3 vreturn v
-- array of functions,-- the first >>= performs 160 / 0, returning Nothing-- the second >>= has to perform Nothing >>= multiply 3 ....-- and simply returns Nothing without calling multiply 3 ....array3 = val1 >>= divideBy 0 >>= multiply 3 >>= divideBy 4 >>= multiply 3
main = doprint array1print (array2 160)print array3
为了说明monad是带有辅助操作的函数数组,请考虑等效于上面的例子,只是使用一个真正的函数数组
type MyMonad = [Int -> Maybe Int] -- my monad as a real array of functions
myArray1 = [divideBy 2, multiply 3, divideBy 4, multiply 3]
-- function for the machinery of executing each function i with the result provided by function i-1runMyMonad :: Maybe Int -> MyMonad -> Maybe IntrunMyMonad val [] = valrunMyMonad Nothing _ = NothingrunMyMonad (Just val) (f:fs) = runMyMonad (f val) fs
# result = ret(0)result = (0, true)# result = result.bind(lambda v: (x, v <= x))result[1] = result[1] and result[0] <= xresult[0] = x# result = result.bind(lambda v: (y, v == y))result[1] = result[1] and result[0] == yresult[0] = y# result = result.bind(lambda v: (3, v < 3))result[1] = result[1] and result[0] < 3result[0] = 3result = result[1] # not explicit part of a monad
一个真正的monad最多计算一次每个参数。
现在想想“结果”变量,你会得到这个链:
ret(0) .bind (lambda v: v <= x) .bind (lambda v: v == y) .bind (lambda v: v < 3)