可能是那个(替代f,可折叠f)=> Monad f?

时间:2017-05-24 11:19:29

标签: haskell monads typeclass

以下类型检查:

instance (Applicative f, Alternative f, Foldable f) => Monad f where 
  (>>=) = flip $ \f -> foldr (<|>) empty . fmap f
  -- Or equivalently
  a >>= b = getAlt . foldMap Alt . fmap b $ a

这实际上是一个有效的Monad实例吗?如果是,为什么不使用它?如果不是,它是否违反任何法律等?我没有证明法律有效,但我也找不到反例。

2 个答案:

答案 0 :(得分:7)

这应该是正确的身份单一法律的反例。

下面,我们从GHC.Generics开始使用仿函数产品instance Monad,但如果愿意,可以将其内联。这也是一个应用,替代,可折叠和monad。我相信这些实例上的图书馆是守法的。

然后我们将建议的{-# LANGUAGE FlexibleInstances, GeneralizedNewtypeDeriving, TypeOperators #-} {-# OPTIONS -Wall #-} module NotAMonad where import Control.Applicative import GHC.Generics ((:*:)(..)) -- A basic wrapper to avoid overlapping instances, and to be able to -- define a custom monad instance. newtype Wrap m a = Wrap { unWrap :: m a } deriving (Functor, Applicative, Alternative, Foldable, Show) -- The proposed instance instance (Applicative f, Alternative f, Foldable f) => Monad (Wrap f) where (>>=) = flip $ \f -> foldr (<|>) empty . fmap f -- This is Applicative, Alternative, and Foldable type T = Maybe :*: Maybe -- A basic test test :: Wrap T Int test = Wrap (Just 3 :*: Just 4) >>= return -- result: -- Wrap {unWrap = Just 3 :*: Just 3} (问题中的那个)与标准库1进行比较。我们发现拟议的实例不满足正确的身份法,而它似乎在图书馆实例中持有(至少在我非常有限的测试中)。

4

现在,3已被Just 3 <|> Just 4 = Just 3取代。不过,我没有试图解释原因。 我想这是由> (Just 3 :*: Just 4) >>= return Just 3 :*: Just 4 引起的。

使用库monad实例,一切看起来都很好:

<?php
function dash()
{
  include 'config.php';
  $sql = "SELECT  RoomNumber  FROM roommaster ";
  if ($result = mysqli_query($db, $sql)) {
    $str = '';
    while ($row = mysqli_fetch_array($result)) {
      // generate array from comma delimited list
      $rooms = explode(',', $row['RoomNumber']);
      //create the dynamic button and set the value
      foreach ($rooms as $v) {
        $str .= "<input type='button'  name='b1' id='btn' value='" . $v . "' />";
      }
    }
    return $str;
  } else {
    echo "ERROR: Could not able to execute $sql. " . mysqli_error($db);
  }
  mysqli_close($db);
}
?>

<!Doctype html>
<html>

<head>
  <meta charset="UTF-8">
  <title>room boking</title>

  <link href="css/bootstrap1.min.css" rel="stylesheet">
  <link rel="stylesheet" href="css/front.css">
  <script src='http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script>
  <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>

</head>

<body>
  <form mathod="post" action="booking.php">
    <div class="  row box col-md-4">
      <div style="color:black">
        <?php echo dash();?>
      </div>
    </div>


  </form>


</body>

</html>

答案 1 :(得分:5)

Alternative是一个hacky野兽。它本质上是 monoid构造函数的类:类型构造函数T,对于任何包含的类型XT X是一个幺半群。这与functor ... monad并没有多大关系,并且数学上的深度要小得多。 (所以,只有数学上的优雅,在Monad下设置Alternative会有点不好。)

为了清楚起见,我们用Monoid来编写该实例(这实际上不会编译):

instance (Foldable f, (∀ x . Monoid (f x))) => Monad f where
  (>>=) = flip $ \f -> foldr mappend empty . fmap f
        ≡ flip $ \f -> fold . fmap f
        ≡ flip foldMap

或确实

  (=<<) = foldMap

所以,这绝对不是未知的事情。

为了检查法律,我们最好看看Kleisli的表述:

  (f <=< g) x = f =<< g x
              ≡ foldMap f $ g x

  f <=< g = foldMap f . g

然后是monad法则

  • 左侧身份

    f <=< pure ≡ foldMap f . pure =! f
    
  • 正确的身份

    pure <=< f ≡ foldMap pure . f =! f
    
  • 结合性

    (f <=< g) <=< h ≡ foldMap (foldMap f . g) . h
                    =! foldMap f . foldMap g . h
                    ≡ foldMap f . (foldMap g . h) ≡ f <=< (g <=< h)
    

所以简而言之,我们需要

  • foldMap f . pure =! f =! foldMap pure . ff
  • foldMap (foldMap f . g) =! foldMap f . foldMap gfg

这当然看起来并非不合理,但我不认为你是否可以为任意Foldable + Alternative个实例严格地作出结论。

真的,我在这个实例中看到的一个大问题是它不够通用。大多数monad既不是Foldable也不是Alternative。如果有一个覆盖所有的定义,例如你建议的定义,则需要OverlappingInstances来定义你自己的任何实例,而这些通常被认为是你没有充分理由不应该使用的。

我确实想知道绑定方法的以下默认定义是否会出现任何问题:

{-# LANGUAGE DefaultSignatures #-}
class Applicative f => Monad f where
  return :: a -> m a
  return = pure
  (>>=) :: m a -> (a -> m b) -> m b
  default (>>=) :: (Foldable m, Monoid m b)
          => m a -> (a -> m b) -> m b
  (>>=) = flip foldMap

这至少可以定义例如列表实例简单为

instance Monad []

,根本不需要写出方法,foldMap ≡ concatMap ≡ (=<<)