Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 创建用于增量存储结果类型不匹配的monad_Haskell_Monads - Fatal编程技术网

Haskell 创建用于增量存储结果类型不匹配的monad

Haskell 创建用于增量存储结果类型不匹配的monad,haskell,monads,Haskell,Monads,我试图通过创建单子来更好地理解单子。其想法是创建一个只存储所有结果的monad。然而,我就是找不到匹配的类型 main :: IO () main = do let v1 = return (1,1) v2 = return (8,8) x = move v1 v2 print x newtype Accum a = Accum { open :: (a, [a]) } deriving (Show) instance

我试图通过创建单子来更好地理解单子。其想法是创建一个只存储所有结果的monad。然而,我就是找不到匹配的类型

main :: IO ()
main = do
    let 
        v1 = return (1,1)
        v2 = return (8,8)
        x = move v1 v2
    print x


newtype Accum a = Accum { open :: (a, [a]) }
  deriving (Show)

instance Monad Accum where
    return v = Accum (v, [v])
    (>>=) m f = let (r1, l1) = open m
                    r2       = f r1
                    (r3, l3) = open r2
                in Accum (r3, l1 ++ l3)

move :: Accum (Int,Int) -> Accum (Int,Int) -> Accum (Int,Int)
move p1 p2 = do
    (x1,y1) <- p1
    (x2,y2) <- p2
    return (x1+x2, y1+y2)
main::IO()
main=do
让
v1=返回值(1,1)
v2=返回值(8,8)
x=移动v1 v2
打印x
新类型Accum a=Accum{open::(a[a])}
派生(显示)
实例Monad Accum在哪里
返回v=累计(v,[v])
(>>=)mf=let(r1,l1)=开m
r2=f r1
(r3,l3)=打开r2
累计(r3,l1++l3)
移动::Accum(Int,Int)->Accum(Int,Int)->Accum(Int,Int)
移动p1 p2=do

(x1,y1)您的代码与
Writer[a]
monad非常相似,我认为除了命名之外,没有比缩小所有方面的差距更简单的修复方法了。具体而言:

由于monad必须允许任意结果类型,因此效果部分的类型不能依赖于结果部分的类型,因此将类型定义更改为

newtype Accum a b = Accum { open :: (b, [a]) }
为了满足monad定律,
return
不能具有非平凡的效果,因此将其定义更改为

return v = Accum (v, [])
现在您需要有一个显式的操作来存储,也就是MonadWriter中的
tell

tell as = Accum ((), as)
最后,根据需要更改类型签名以包含额外的类型参数。

我将您的请求理解为

创建一个记录所有中间结果的单子

这样的事情在哈斯克尔是不可能存在的。首先,单子必须是函子。我想你已经知道那是什么了

我只看到
fmap
的两个实现大致保持了“记录计算”语义并通过了类型检查:

fmap f (Accum (x,xs)) = Accum (f x, map f xs) -- map history
fmap f (Accum (x,xs)) = Accum (f x,[]) -- forget history
第一种方法使您的
acum a
与非空列表相同
[a]
,众所周知,列表是monad实例;不完全是你想要的。 第二种更为乏味

当您使用bind(
>=
)从函子转换为单子时,情况并没有变得更好

正如厄尔詹·约翰森已经指出的那样,
ma
中的
a
可以是任何类型。当你想更好地理解单子时,不妨这样做:在
ma
中,让
a
成为
ma
本身。现在你有了
m(ma)
。对于每个单子,都有一个方法

join :: m (m a) -> m a
这将删除一级嵌套。可以将列表列表转换为列表,将树树树转换为树,并通过逐个执行将生成IO操作的IO操作转换为单个操作


我必须克制住再写一篇蹩脚的单子教程的冲动…

我相信这样的例子会违反单子定律,例如,
return x>>=return
并不等同于
return x
。你确定你想要的不是这个吗?可能是,但我只想要一个简单的简化版本,看看它是如何连接在一起的。