【问题标题】:Redefine list monad instance重新定义列表单子实例
【发布时间】:2012-07-21 05:54:06
【问题描述】:

我想为列表单子提供我自己的实例。不幸的是,以下导致编译时重复实例声明错误。

myReturn :: a -> [a]
myBind :: [a] -> (a -> [b]) -> [b]
instance Monad [] where
    return = myReturn
    (>>=) = myBind

从文档来看,导入时似乎无法隐藏实例声明,而且由于 list monad 实例已经在前奏中声明,我想我也无法摆脱导入本身。

我想也许我至少可以重新绑定(>>=)return,这样我就可以使用我自己的实现来使用do 块,因为do 块据说只是(>>=) 和@987654326 应用程序的语法糖@。

let
    return = myReturn
    (>>=) = myBind
in
    do
        item1 <- list1
        item2 <- list2
        return (item1, item2)

不幸的是,块似乎是从其他地方获取(&gt;&gt;=),因为它仍在使用默认列表单子实例的(&gt;&gt;=)

有什么方法可以让我的 (&gt;&gt;=)return 实现成为 list monad 的一个实例,或者至少可以将它们与 do 块一起使用?

【问题讨论】:

  • 请记住,monad 实现Monad 类型类的方法是不够的,每个 monad 实例都应该遵守“monad 法则”haskell.org/haskellwiki/Monad_Laws。如果一个实例不遵守单子定律,计算可能会导致错误的结果。
  • 参见 RebindableSyntax 。

标签: haskell functional-programming monads typeclass


【解决方案1】:

您可以将列表包装在新类型中

newtype MyList a = MyList { unMyList :: [a] }

并为此包装类型声明您的实例

instance Monad MyList where
    return = MyList . myReturn
    (MyList m) >>= f = MyList . myBind m f

现在只需将列表包装在 newtype 包装器 MyList 中(newtypes 只是语法糖,因此在编译时会被删除)。

【讨论】:

    【解决方案2】:

    您不能为列表定义另一个 Monad 实例,在某些情况下您可以定义一个新类型来解决这个问题,但您必须手动将所有列表函数提升到新类型才能使用它们。

    要在 do-blocks 中仅使用您自己的 (&gt;&gt;=)return,您可以使用带有 GHC 的语言扩展:

    {-# LANGUAGE NoImplicitPrelude #-}
    module ListMon where
    
    import Prelude hiding ((>>=), return)
    
    (>>=) :: [a] -> (a -> [b]) -> [b]
    xs >>= foo = case xs of
                   [] -> [undefined]
                   [x] -> foo x ++ foo x
                   ys -> take 10 $ concatMap foo $ take 5 ys
    
    return :: a -> [a]
    return x = [x,x,x]
    
    someList :: [Int]
    someList = do
        k <- [1 .. 4]
        h <- [2 .. 3]
        return (k + 12*h)
    

    导致

    $ ghci ListMon
    {- snip loading messages -}
    [1 of 1] Compiling ListMon          ( ListMon.hs, interpreted )
    Ok, modules loaded:
    *ListMon> someList 
    [25,25,25,37,37,37,26,26,26,38,38,38,27,27,27,39,39,39,28,28,28,40,40,40]
    

    对于NoImplicitPrelude,do-notation 的脱糖使用范围内的(&gt;&gt;=)return

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-22
      • 2021-03-09
      • 1970-01-01
      相关资源
      最近更新 更多