在Haskell中从头定义monad
在研究了Haskell中的单子之后——这是一个非常吸引人的主题——我想知道我是否可以自己定义一个单子,而不用使用已经定义好的类型类 我不想让在Haskell中从头定义monad,haskell,monads,functor,Haskell,Monads,Functor,在研究了Haskell中的单子之后——这是一个非常吸引人的主题——我想知道我是否可以自己定义一个单子,而不用使用已经定义好的类型类 我不想让Monad成为Functor的一个实例,我只想定义一个Monad本身,它有自己的fmap函数(我还想更改一些函数名,比如return并将其称为unit) monad可以由bind操作符(>>=)和函数return定义,但也可以根据return和join定义,因为最后一个函数可以用bind操作符来表示:join m=m>=id。因此,monad(从技术上)可以
Monad
成为Functor
的一个实例,我只想定义一个Monad本身,它有自己的fmap
函数(我还想更改一些函数名,比如return
并将其称为unit
)
monad可以由bind操作符(>>=)
和函数return
定义,但也可以根据return
和join
定义,因为最后一个函数可以用bind操作符来表示:join m=m>=id
。因此,monad(从技术上)可以定义为return
和join
等。函数fmap
是必需的(也是Haskell中存在Functor
的基础),但也可以用return
来定义,因为它也可以(我认为)定义如下:fmap f m=m>=return。f
(在编写编辑之前,fmap f m=return.f
;这显然是一个打字错误)
但我知道这不如使用预定义的Monad
typeclass有效,只是为了更好地理解Haskell语言
我怎样才能做到这一点?这是我脑海中对这个概念的描述,现在,它不是有用的代码:
——只是一个草图
infixr 9∘
(∘) :: (b->c)->(a->b)->a->c
(∘) g f x=g(f x)
--(f)∘ g) x=f(gx)
--我自己的“fmap”
--映射器id=id
--制图员(f∘ g) =映射器f∘ 映射器g
--我的单子
类MyMonadBase(m::*->*),其中
单位::a->m a--退货
join::m(MA)->m a
join=(>>=id)
映射器f m=m>>=单位∘ F
--测试:
数据树a=叶a |分支(树a)(树a)
实例MyMonadBase树,其中
单位=叶
连接(叶x)=x
连接(分支l r)=分支(连接l)(连接r)
我是否在正确的轨道上(概念上)?一些小的修正: monad可以由bind操作符
(>>=)
和函数return
定义,但也可以根据return
和join
定义,因为最后一个函数可以用bind操作符来表示:join m=m>=id
结论(“[a monad]也可以用返回
和连接
”来定义)是正确的,但前提是(“因为[连接
]可以用绑定运算符来表示”)这并不意味着它。相反,您必须表明您要忽略的运算符--bind运算符--可能是根据您拥有的内容定义的--return
和join
。一旦您尝试这样做,您就会明白为什么单子也是一个函子是如此重要:
m >>= f = join (fmap f m)
函数fmap
是必需的(也是Haskell中存在Functor
的基础),但也可以定义为return
,因为它也可以(我认为)定义如下:fmap f m=return.f
这不是对fmap
的正确定义,你应该怀疑,因为右边没有提到m
!正确的版本应该是:
fmap f m = m >>= return . f
但是现在这是一个循环定义,因为上面我们计划用fmap
来定义(>>=)
。所以如果您想让返回和加入Monad
的基本操作,您确实需要单独实现fmap
我知道这不如使用预定义的Monad
typeclass有效
我看不出有任何理由先验地相信这一点。之所以选择(>>=)
而不是join
,不是因为它更高效,而是因为在编程中使用单子时,这是一种自然的操作
至于您的实际代码,我认为它看起来不错,但有两个警告:
我强烈怀疑您对mapper
的定义与您认为的不一样。在mapper id=id
行中,左侧的模式id
匹配所有传入值,右侧的变量id
返回的值不变。行mapper(f∘ g) =映射器f∘ mapper g
是无效的Haskell。(也许这两行是用来记录mapper
所需的法律,而不是实际的代码?)
就(>>=)
而言,提供join
和mapper
的默认实现是很奇怪的——这两种实现都是出于上述原因(所有三种都是基本的,必须定义),并且因为(>>=)
不是类操作,因此用户无法以有意义的方式定义
一些小的修正:
monad可以由bind操作符(>>=)
和函数return
定义,但也可以根据return
和join
定义,因为最后一个函数可以用bind操作符来表示:join m=m>=id
结论(“[a monad]也可以用返回
和连接
”来定义)是正确的,但前提是(“因为[连接
]可以用绑定运算符来表示”)这并不意味着它。相反,您必须表明您要忽略的运算符--bind运算符--可能是根据您拥有的内容定义的--return
和join
。一旦您尝试这样做,您就会明白为什么单子也是一个函子是如此重要:
m >>= f = join (fmap f m)
函数fmap
是必需的(也是Haskell中存在Functor
的基础),但也可以根据返回定义,因为它可能