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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/google-maps/4.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 为什么单子变压器不同于堆叠单子?_Haskell_Monads_Monad Transformers_Category Theory - Fatal编程技术网

Haskell 为什么单子变压器不同于堆叠单子?

Haskell 为什么单子变压器不同于堆叠单子?,haskell,monads,monad-transformers,category-theory,Haskell,Monads,Monad Transformers,Category Theory,在许多情况下,我不清楚通过将两个单子与一个转换器组合而不是使用两个单独的单子可以得到什么。显然,使用两个单独的单子是一件麻烦的事,可能会在do符号中包含do符号,但在某些情况下,它的表达能力不够吗 一种情况似乎是列表上的StateT:组合monad并不能得到正确的类型,如果您确实通过一堆monad(如Bar)获得正确的类型(其中Bar a=(Reader r(List)(Writer w(Identity a))),它就做不到正确的事情 但我想更全面、更技术地了解monad Transforme

在许多情况下,我不清楚通过将两个单子与一个转换器组合而不是使用两个单独的单子可以得到什么。显然,使用两个单独的单子是一件麻烦的事,可能会在do符号中包含do符号,但在某些情况下,它的表达能力不够吗

一种情况似乎是列表上的StateT:组合monad并不能得到正确的类型,如果您确实通过一堆monad(如Bar)获得正确的类型(其中Bar a=(Reader r(List)(Writer w(Identity a))),它就做不到正确的事情

但我想更全面、更技术地了解monad Transformer到底带来了什么,何时需要,何时不需要,以及为什么

要使这个问题更加集中,请执行以下操作:

  • 一个没有相应转换器的monad的实际例子是什么(这将有助于说明转换器可以做什么,而堆叠monad却做不到)
  • StateT和ContT是唯一一种类型不等同于它们与m的组合的转换器,对于底层的monad m(无论它们的组合顺序如何)
  • (我不感兴趣的是关于不同库选择的具体实现细节,而是一般性的(可能是Haskell无关的)问题,即单体变换器/变形器添加了什么作为通过堆叠一组单体类型构造函数组合效果的替代方案。)

    (我是一位语言学家,我正在做一个项目,用一个单子变换器堆栈来丰富蒙塔古语法——简单地键入lambda演算,将单词的意思组合成句子。了解变换器是否真的对我有用真的很有帮助。)

    谢谢

    鲁本

    一个没有相应转换器的monad的实际例子是什么(这将有助于说明转换器可以做什么,而堆叠monad却做不到)

    IO
    ST
    是这里的典型例子

    StateT和ContT是唯一一种类型不等同于它们与m的组合的转换器,对于底层的monad m(无论它们的组合顺序如何)

    不,不是(同构于)
    [MA]

    newtype ListT m a =
      ListT { unListT :: m (Maybe (a, ListT m a)) }
    

    要回答您关于
    Writer w(maybea a)
    MaybeT(Writer w)a
    之间区别的问题,让我们先看看定义:

    newtype WriterT w m a = WriterT { runWriterT :: m (a, w) }
    type Writer w = WriterT w Identity
    
    newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }
    
    使用
    ~
    表示“结构类似于”,我们有:

    所以从某种意义上说,你是正确的——从结构上说,你是
    Writer w(可能是a)
    MaybeT(Writer w)a
    都是一样的-两者本质上只是一对a值和a
    w

    区别在于我们如何将它们视为一元值。
    返回
    >=
    类函数根据不同的情况执行不同的操作 他们属于哪个单子

    让我们考虑这两个代码<代码>(仅3,[]::[String ])< /代码>。 我们在上面推导了这一对在两个单子中的表达方式:

    three_W :: Writer String (Maybe Int)
    three_W = return (Just 3)
    
    three_M :: MaybeT (Writer String) Int
    three_M = return 3
    
    下面是我们如何构造一对
    (Nothing,[])

    现在考虑这对函数:

    add1 :: (Maybe Int, String) -> (Maybe Int, String)
    add1 (Nothing, w) = (Nothing w)
    add1 (Just x, w)  = (Just (x+1), w)
    
    让我们看看如何在两个不同的monad中实现它:

    add1_W :: Writer String (Maybe Int) -> Writer String (Maybe Int)
    add1_W e = do x <- e
                 case x of
                   Nothing -> return Nothing
                   Just y  -> return (Just (y+1))
    
    add1_M :: MaybeT (Writer String) Int -> MaybeT (Writer String) Int
    add1_M e = do x <- e; return (e+1)
      -- also could use: fmap (+1) e
    
    可以在任何具有写入器字符串的monad堆栈中不加更改地使用,例如:

    WriterT String IO
    ReaderT (WriterT String Maybe)
    MaybeT (Writer String)
    StateT (WriterT String (ReaderT Char IO))
    ...
    
    但是
    square
    的返回值没有针对
    编写器字符串(可能是Int)
    进行类型检查,因为
    square
    没有返回
    可能是

    当您在
    编写器字符串(可能是Int)
    中编码时,代码会显式地显示 单子的结构使它不那么通用。
    add1\u W

    add1_W e = do x <- e 
                  return $ do 
                    y <- x 
                    return $ y + 1
    

    add1_W e=do x“使用两个单独的monad”是什么意思?你能举个例子吗?列表monad有点特殊,因为任何作为列表的表达式也是列表monad中的一个值。尝试“堆栈”Writer和IO-
    Writer W(IO a)
    Writer
    单子中返回
    IO a
    的一个值,这与
    Writer w IO a
    不同,后者是
    Writer w IO
    单子中返回
    a
    的一个值。嗯,IO也可能不是最好的例子。那么(Writer w(可能a))与(MaybeT(Writer w)a)呢?我认为,这些都是相同的类型,经过必要的修改后,它们的作用也一样。一个单子变换器只是一个类型
    t
    ,其中
    tm
    是一个
    monad
    ,对于任何
    monad
    m。然而,一般来说,两个单子的组合不是一个单子-因此,没有太多的抽象操作(如果有的话)可以用两个单子的组合来定义(如果没有抽象,在Haskell中用单子编程将是非常乏味的)。这只是巧合,大多数转换器通常会遇到单子的组合(即
    WriterT x m
    Compose m(x,)
    )@user2407038我不确定大多数变形金刚最终看起来都像合成变形金刚是不是巧合。制作变形金刚最简单的方法是粗略地看一看,对于某个特定的单子,它与任何其他单子的合成都是单子。我们可以用特定的单子(实现特定于该单子)来实现这一点但并不是所有的都是变压器的基本来源。你说得对,这不是必要的,但这不是巧合。可能有意思的是,它仍然几乎是合成,你只需要将合成移动到固定点下:
    List a=Fix(1+a*x)
    ListT m a=Fix(m∘ (1+a*x))
    我认为没有人知道没有转换器的monad的显式示例。IO和ST monad是不透明的-它们不是作为显式类型表达式给出的,它们是由库以某种方式在低级别实现的。所有已知的显式monad都有transformer
    square x = do tell ("computing the square of " ++ show x)
                  return (x*x)
    
    WriterT String IO
    ReaderT (WriterT String Maybe)
    MaybeT (Writer String)
    StateT (WriterT String (ReaderT Char IO))
    ...
    
    add1_W e = do x <- e 
                  return $ do 
                    y <- x 
                    return $ y + 1