Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.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,但是我的Monad实例没有编译 我想做一些类似的事情: add5 7 >>= add7 此代码必须返回19[5+7>>=12+7] 我实现的代码是: newtype MyType a = MyType ( a -> a) instance Monad MyType where MyType comm >>= comm2 = MyType (\inp -> let

我已经开始通过实现一个简单的示例来研究Monad,但是我的Monad实例没有编译

我想做一些类似的事情:

add5 7 >>= add7
此代码必须返回19[5+7>>=12+7]

我实现的代码是:

newtype MyType a = MyType ( a -> a)

instance Monad MyType where
    MyType comm  >>= comm2  = MyType (\inp -> let
                                        value = comm inp 
                                        MyType comm2' = comm2
                                        in  comm2' value)
    return  x       = MyType (\input -> input)


add5 :: MyType Integer
add5 = MyType (\inp -> inp + 5)

add7 :: MyType Integer
add7 = MyType (\inp -> inp + 7)
当我通过注释Monad实例块调用add5和add7而不使用bind操作符时,它可以工作:

main =  do 
        let MyType x = add5
        let MyType y = add7
        putStrLn $ show $ x $ y 7
输出错误为:

new1.hs:5:94:
    Couldn't match expected type `a' with actual type `b'
      `a' is a rigid type variable bound by
          the type signature for
            >>= :: MyType a -> (a -> MyType b) -> MyType b
          at new1.hs:4:9
      `b' is a rigid type variable bound by
          the type signature for
            >>= :: MyType a -> (a -> MyType b) -> MyType b
          at new1.hs:4:9
    In the first argument of `comm', namely `inp'
    In the expression: comm inp
    In an equation for `value': value = comm inp

new1.hs:6:97:
    Couldn't match expected type `MyType t0'
                with actual type `a -> MyType b'
    In the expression: comm2
    In a pattern binding: MyType comm2' = comm2
    In the expression:
      let
        value = comm inp
        MyType comm2' = comm2
      in comm2' value

你不需要单子来做你想做的事。相反,您可以使用:

>>>函数只是合成运算符,即。对于函数实例,其参数翻转。因此,您可以简单地执行以下操作:

Prelude> let add5 = (+5)
Prelude> let add7 = (+7)
Prelude> let add12 = add7 . add5
Prelude> add12 7
19
已经有一个函数的monad实例。它被称为阅读器monad:

它使您可以执行以下操作:

a2-minus-b2 = \a -> do
    a-minus-b <- (\b -> a - b)
    a-plus-b  <- (\b -> a + b)
    return (a-minus-b * a-plus-b)

然而,我只是想向您展示一下读卡器monad可以用来做什么。

您走错了方向。MyType不能是单子。 MyType唯一可能的monad实例实现相当简单,并且不能使add5 7>>=add7等于19

>>=必须具有类型

MyType a -> (a -> MyType b) -> MyType b -- remove newType
(a -> a) -> (a -> (b -> b)) -> (b -> b)
typechecks的唯一功能是

(MyType _) >>= _  = MyType (\input -> input)
这与您的return实现非常相似。我们通常在haskell中写入id而不是\input->input

为什么我声称这是唯一的功能? 再次检查简化类型签名a->a->b->b->b->b:如果没有a作为输入,则无法计算>>=、a->a和a->b->b的参数

这不符合monad定律:x>>=return=x

它不能是单子,因为它甚至不是函子,因为类型变量处于逆变位置

这意味着您无法实施:

fmap :: (a->b)->MyType a->MyType b

您可以使用f::a->b将a->a中的结果类型更改为a->b,但您不能将该函数的参数类型更改为获取b->b,这是构造MyType b所需的。我不确定您实际想要做什么。如果您只是想获得代码示例

add5 7 >>= add7
用显而易见的方式将数字相加,得到19的结果,这很简单,任何单子都可以。因此,我们可以选择最简单的单子,身份单子:

newtype Id a = Id { runId :: a }

instance Monad Id where
  return x   = Id x
  Id x >>= f = f x
请注意,这段代码将在GHC 7.8中产生警告,因为在将来,Applicative将成为monad的一个超类,您必须定义其他实例。对于这个例子,它们是不相关的,所以我将省略它们

现在您可以定义add5和add7:

如果省略类型签名并询问GHCi,您将看到这两个定义实际上都有更通用的类型Num a,Monad m=>a->ma。这就是我说你的例子对任何单子都有效的意思

您可以尝试在GHCi中实现这一切:

GHCi> :t add5 7 >>= add7 
add5 7 >>= add7 :: Id Int
GHCi> runId (add5 7 >>= add7)
19

我不确定你能不能为这种类型的自形函数创建一个Monad实例。除去新类型包装器,您需要使用类型a->a->a->b->b->b->b来实现a>>=。如果允许参数类型独立于结果类型,则可以创建Monad实例,尽管这将是Reader Monad。如果我错了,请纠正我,但我认为函数的Reader和Monad实例是完全无关的。瞧,这个答案基本上是不可信的。是的,你可以实现fmap。我的答案的第一次修改几乎是你的。但是fmap f MyType g=MyType id类型检查。但是违反了id函子法则。@Franky这是一个无用的实现。你也可以叫它Const。您也可以随时插入未定义的。关键是它必须适用于任何a->a。fmap实现与OP的返回一样无用。@Franky我认为你的建议更糟糕,因为它确实断言任何a作为类型都可以映射到a->a作为类型-但a->a中只有一个点表现良好。@Franky换句话说,如果你有一个包含对象a->a的类别,他们之间有一些箭。他们的组成是什么?然后将其嵌入Hask中。在映射函数的组合时,fmap也必须命中该组合。你可能想假装这是一个常数,但我不相信;您需要显示a->a-first之间箭头的组合。
fmap :: (a->b)->MyType a->MyType b
add5 7 >>= add7
newtype Id a = Id { runId :: a }

instance Monad Id where
  return x   = Id x
  Id x >>= f = f x
add5 :: Id Int
add5 n = return (n + 5)

add7 :: Id Int
add7 n = return (n + 7)
GHCi> :t add5 7 >>= add7 
add5 7 >>= add7 :: Id Int
GHCi> runId (add5 7 >>= add7)
19