gpt4 book ai didi

haskell - monad 和 monad 函数的类约束

转载 作者:行者123 更新时间:2023-12-03 15:09:44 28 4
gpt4 key购买 nike

我正在尝试编写一个只能包含 Num 的新 monad。当它失败时,它返回 0,就像 Maybe monad 在失败时返回 Nothing 一样。

这是我到目前为止所拥有的:

data (Num a) => IDnum a = IDnum a

instance Monad IDnum where
return x = IDnum x
IDnum x >>= f = f x
fail :: (Num a) => String -> IDnum a
fail _ = return 0

Haskell 提示说有
No instance for (Num a) arising from a use of `IDnum'

它建议我在每个 monad 函数的类型签名的上下文中添加一个 add (Num a),但是我尝试了它,然后它提示他们需要“forall”a 工作。

前任:
Method signature does not match class; it should be
return :: forall a. a -> IDnum a
In the instance declaration for `Monad IDnum'

有谁知道如何解决这一问题?

最佳答案

现有Monad typeclass 期望您的类型适用于每个可能的类型参数。考虑Maybe : 在 Maybe a , a完全不受约束。基本上 你不能有一个带有约束的 Monad .

这是 Monad 的基本限制。类已定义——我不知道有什么方法可以在不修改它的情况下绕过它。

这也是定义Monad的问题。其他常见类型的实例,例如 Set .

在实践中,这个限制实际上非常重要。考虑(通常)函数不是 Num 的实例。 .这意味着我们不能使用你的 monad 来包含一个函数!这确实限制了重要的操作,如 ap ( <*> 来自 Applicative ),因为这取决于包含函数的 monad:

ap :: Monad m => m (a -> b) -> m a -> m b

您的 monad 将不支持我们从普通 monad 中获得的许多常见用途和习语!这宁愿限制它的效用。

此外,作为旁注,您通常应该避免使用 fail .它并不真正适合 Monad typeclass:这更像是一个历史性的事故。大多数人都同意你应该避免它:它只是一种在 do-notation 中处理失败的模式匹配的技巧。

也就是说,看看如何定义一个受限的 monad 类对于理解一些 Haskell 扩展和学习一些中级/高级 Haskell 是一个很好的练习。

备择方案

考虑到缺点,这里有几个替代方案——标准 Monad 的替代品。支持受限单子(monad)的类。

约束种类

我可以想到几个可能的替代方案。最现代的将利用 ConstraintKind GHC 中的扩展,它允许您将类型类约束具体化为种类。 This blog post详细说明如何使用约束类型来实现受限的 monad;看完之后,我会在这里总结一下。

基本思想很简单:使用 ConstraintKind ,我们可以将约束 ( Num a) 转换为类型。然后我们可以有一个新的 Monad包含此类型作为成员的类(就像 returnfail 是成员)并允许使用 Num a 重载约束.这是代码的样子:
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TypeFamilies #-}

module Main where

import Prelude hiding (Monad (..))

import GHC.Exts

class Monad m where
type Restriction m a :: Constraint
type Restriction m a = ()

return :: Restriction m a => a -> m a
(>>=) :: Restriction m a => m a -> (a -> m b) -> m b
fail :: Restriction m a => String -> m a

data IDnum a = IDnum a

instance Monad IDnum where
type Restriction IDnum a = Num a
return = IDnum
IDnum x >>= f = f x
fail _ = return 0

单子(monad)

有一个现有的关于 hackage 的库,名为 rmonad (对于“restricted monad”),它提供了一个更通用的类型类。您可能可以使用它来编写您想要的 monad 实例。 (我自己没用过,所以有点难说。)

它不使用 ConstraintKinds扩展并且(我相信)支持旧版本的 GHC。但是,我认为这有点难看;我不确定这是否是最佳选择。

这是我想出的代码:
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}

import Prelude hiding (Monad (..))

import Control.RMonad
import Data.Suitable

data IDnum a = IDnum a

data instance Constraints IDnum a = Num a => IDnumConstraints
instance Num a => Suitable IDnum a where
constraints = IDnumConstraints

instance RMonad IDnum where
return = IDnum
IDnum x >>= f = f x
fail _ = withResConstraints $ \ IDnumConstraints -> return 0

延伸阅读

更多详情,请查看 this SO question .

Oleg 有一篇与 Set monad 相关的文章,这可能很有趣: "How to restrict a monad without breaking it" .

最后,您还可以阅读几篇论文:
  • The Constrained-Monad Problem
  • Generic Monadic Constructs for Embedded Languages
  • 关于haskell - monad 和 monad 函数的类约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22313903/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com