Monads可以做许多惊人的,疯狂的事情.他们可以创建具有值叠加的变量.它们可以允许您在计算之前访问未来的数据.它们可以让您编写破坏性更新,但不是真的.然后延续monad让你打破人们的思想!通常是你自己的.;-)
但这是一个挑战:你能制作一个可以暂停的单子吗?
data Pause s x instance Monad (Pause s) mutate :: (s -> s) -> Pause s () yield :: Pause s () step :: s -> Pause s () -> (s, Maybe (Pause s ()))
该Pause单子是一种状态的单子(因此mutate,具有明显的语义).通常情况下,像这样的monad具有某种"运行"功能,它运行计算并将您送回最终状态.但Pause它是不同的:它提供了一个step函数,它运行计算直到它调用魔法yield函数.这里计算暂停,返回给调用者足够的信息以便稍后恢复计算.
额外的awesomness:允许调用者修改step调用之间的状态.(例如,上面的类型签名应该允许这样做.)
使用案例:编写执行复杂操作的代码通常很容易,但是要将其转换为也在其操作中输出中间状态的总PITA .如果您希望用户能够在执行过程中途改变某些内容,那么事情变得非常复杂.
实施思路:
显然它可以用线程,锁和IO.但我们能做得更好吗?;-)
继续monad疯狂的东西?
也许是某种编写器monad,yield只记录当前状态,然后我们可以step通过迭代日志中的状态来"假装" 它.(显然这排除了改变步骤之间的状态,因为我们现在并没有真正"暂停"任何东西.)
这个问题来自于一个应用而非Monad的仿函数的例子中的答案 :它声称是
data PoE a = Empty | Pair a a deriving (Functor,Eq)
Run Code Online (Sandbox Code Playgroud)
不能有monad实例,但我没有看到:
instance Applicative PoE where
pure x = Pair x x
Pair f g <*> Pair x y = Pair (f x) (g y)
_ <*> _ = Empty
instance Monad PoE where
Empty >>= _ = Empty
Pair x y >>= f = case (f x, f y) of
(Pair x' _,Pair _ y') -> Pair x' y'
_ -> Empty
Run Code Online (Sandbox Code Playgroud)
实际的原因,我相信这是一个单子是,它是同构于Maybe (Pair …
在尝试找到可以逐步执行/允许线程化的haskell monad时,我发现了自由monad
data Free f a = Return a | Roll (f (Free f a))
Run Code Online (Sandbox Code Playgroud)
用它的monad实例
instance (Functor f) => Monad (Free f) where
return = Return
Return x >>= f = f x
Roll action >>= f = Roll $ fmap (>>= f) action
Run Code Online (Sandbox Code Playgroud)
和它的仿函数实例
instance (Functor f) => Functor (Free f) where
fmap f (Return x) = Return (f x)
fmap f (Roll x) = Roll $ fmap (fmap f) x
Run Code Online (Sandbox Code Playgroud)
我知道每个monad都是一个带有pure = return和的应用函子(<*>) = …
我有一个模拟很多函数的调用type F = A -> B -> C -> D,其中A.. D是具体的类型.
类型的对象A具有中等寿命.(这是codegolf的ratrace的基因组.)
最昂贵的计算来自参数A.我可以像这样容易地记忆:
f1 :: F
f1 a = let expensive = trace "expensive computation!" $ expensiveComputation a
in \b c -> expensive
Run Code Online (Sandbox Code Playgroud)
并expensive通过部分应用保留一些预处理值:
preProz :: [B -> C -> D]
preProz = [f1 [], f1 [False], f2 []]
Run Code Online (Sandbox Code Playgroud)
这些痕迹表明preProz <*> [[],[[]]] <*> [1,2]我不会重新计算这些值.
现在我发现我F的一些人也会受益于预处理B.这种预处理是独立的A,事实上,这样的记忆没有任何好处
f2 a …Run Code Online (Sandbox Code Playgroud) 对于List,为什么right apply (*>)表现为重复并附加第二个参数n次数,n第一个参数的长度在哪里?
ghci> [1,2,3] *> [4,5]
[4,5,4,5,4,5]
Run Code Online (Sandbox Code Playgroud) ADT是免费的monad:
data Free f r = Free (f (Free f r)) | Pure r
Run Code Online (Sandbox Code Playgroud)
我希望它能够得到它,Show以便我可以在使用它时将其打印出来.例如,如果我有以下内容:
data T next = A next | B next deriving (Show)
aa = Free $ A $ Free $ B $ Pure ()
Run Code Online (Sandbox Code Playgroud)
就像现在一样,如果我添加deriving (Show)到FreeADT ,我会收到以下错误:
No instance for (Show (f (Free f r)))
arising from the first field of ‘Free’ (type ‘f (Free f r)’)
Possible fix:
use a standalone 'deriving instance' declaration,
so you can specify the …Run Code Online (Sandbox Code Playgroud) 我正在学习哈斯克尔.当我编译代码时:
data Bintree a = Nulltree | Node (Bintree a) a (Bintree a)
Nulltree :: Bintree a
Run Code Online (Sandbox Code Playgroud)
我收到以下错误:
Invalid type signature: Nulltree :: Bintree a Should be of form <variable> :: <type>
Run Code Online (Sandbox Code Playgroud)
那我该怎么做呢?我试着写:
data Bintree a = Nulltree | Node (Bintree a) a (Bintree a)
Nulltree :: a -> Bintree a
Run Code Online (Sandbox Code Playgroud)
但这会产生同样的错误.
根据我的读数,我了解Monads主要用于:
- 通过将一个函数输出类型与另一个函数输入类型匹配来构成函数.
我认为这是一篇很好的文章:
http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html
它解释了Monads的盒子/包装概念.但是我不明白这些包装用的是什么?除了Composition之外,Wrapper有什么好处?
IO Monad也是一个常见的例子.
name <- getLine -- name has the type String and getLine IO String
Run Code Online (Sandbox Code Playgroud)
那么这种类型差异有什么好处呢?是错误处理吗?
haskell ×8
free-monad ×3
monads ×3
applicative ×2
coroutine ×1
memoization ×1
printing ×1
show ×1