以下类型检查:
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
实例吗?如果是,为什么不使用它?如果不是,它是否违反任何法律等?我没有证明法律有效,但我也找不到反例。
答案 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
,对于任何包含的类型X
,T 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 . f
∀f
foldMap (foldMap f . g) =! foldMap f . foldMap g
∀f
,g
这当然看起来并非不合理,但我不认为你是否可以为任意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 ≡ (=<<)
。