Haskell:实现简单Monad案例研究的问题
我已经开始通过实现一个简单的示例来研究Monad,但是我的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
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