Haskell 同质对的monad实例的已知/已建立用例
有一次我问,哪个被正确地标记为的副本 现在我有一个疑问,对于一对同质类型的monad实例,是否有任何已知的用例 以下是其实例:Haskell 同质对的monad实例的已知/已建立用例,haskell,monads,Haskell,Monads,有一次我问,哪个被正确地标记为的副本 现在我有一个疑问,对于一对同质类型的monad实例,是否有任何已知的用例 以下是其实例: 数据对a=对a派生显示 实例函子对,其中 fmap f(对AB)=对(对FA)(对b) 实例应用程序对,其中 纯a=对a 配对f g配对x y=配对(f x)(g y) 实例Monad对,其中 m>>=f=joinPair(fm) joinPair::对(对a)->对a joinPair(对(对x u)(对y))=对x y 我以前从未使用过这样的单子,但是在给出了这个例
数据对a=对a派生显示
实例函子对,其中
fmap f(对AB)=对(对FA)(对b)
实例应用程序对,其中
纯a=对a
配对f g配对x y=配对(f x)(g y)
实例Monad对,其中
m>>=f=joinPair(fm)
joinPair::对(对a)->对a
joinPair(对(对x u)(对y))=对x y
我以前从未使用过这样的单子,但是在给出了这个例子之后,我看到了它的优点。这将计算两个笛卡尔坐标之间的距离。它实际上似乎非常有用,因为它自动将Xs上的任何操作与Ys上的任何操作分开
collapsePair :: (a -> a -> b) -> Pair a -> b
collapsePair f (Pair x y) = f x y
type Coordinates = Pair Float
type Distance = Float
type TriangleSides = Pair Distance
-- Calculate the sides of a triangle given two x/y coordinates
triangleSides :: Coordinates -> Coordinates -> TriangleSides
triangleSides start end = do
-- Pair x1 y1
s <- start
-- Pair x2 y2
e <- end
-- Pair (x2 - x1) (y2 - y1)
Pair (e - s) (e - s)
-- Calculate the cartesian distance
distance :: Coordinates -> Coordinates -> Distance
distance start end = collapsePair distanceFormula (triangleSides start end)
where distanceFormula x y = sqrt (x ^ 2 + y ^ 2)
但是,我们可以通过人为地将1添加到X的末尾,使其依赖于Monad
:
triangleSides' :: Coordinates -> Coordinates -> TriangleSides
triangleSides' start end = do
s <- start
e <- end
Pair (e - s + 1) (e - s)
您可以验证此答案。您的
对a
与读卡器布尔a
/布尔->a
同构:
to (Pair f t) = \b -> if b then t else f
from f = Pair (f False) (f True)
因此,的任何用例也是monad的潜在用例。这类数据类型的通用术语是可表示函子。距离公式来自,其中三角形的斜边,
c
,在给定边的情况下被找到a
和b
:a^2+b^2=c^2
。哦,好的。谢谢但是,我认为您不需要Monad实例。它比应用程序的(-)end start
做的更多是什么?实际上,您可以执行(.-)=liftA2(-)
,然后执行结束。开始
,可读性强得多。(顺便说一句,发明者+1!)这是一个很好的观点,这个例子可以用Applicative而不是Monad来完成。(do块的最后一行可能是纯(e-s))我想可能有一些中间计算需要Monad用于其他(更好的)计算示例。虽然我们现在无法派生Distributive
,但所有Representable
functor都有一个默认定义:distribute=distributeRep
。Pair
的Monad
实例与Reader
不同。@danidiaz是这样吗?它看起来和我一样。@Enlico是的。这听起来像是与别人对你说的话相矛盾吗?(在我看来不是这样。)@danidiaz,在我看来也一样。@danidiaz,再说一遍,你为什么说他们看起来不一样?你能提供一个具体的例子,说明他们的行为有什么不同吗?
{-# Language DeriveAnyClass #-}
{-# Language DeriveGeneric #-}
{-# Language DeriveTraversable #-}
{-# Language DerivingVia #-}
import Control.Applicative
import Data.Distributive
import Data.Functor.Rep
import GHC.Generics
class (Applicative c, Foldable c) => Coordinates c where
distance :: Floating a => c a -> c a -> a
distance start end = sqrt $ sum $ fmap (^2) $ liftA2 (-) end start
data Triple a = Triple
{ triple1 :: a
, triple2 :: a
, triple3 :: a
}
deriving ( Show, Eq, Ord, Functor, Foldable, Generic1, Representable
, Coordinates )
deriving (Applicative, Monad) via Co Triple
instance Distributive Triple where
distribute f = Triple (triple1 <$> f) (triple2 <$> f) (triple3 <$> f)
> distance (Triple 7 4 3) (Triple 17 6 2)
10.246950765959598
to (Pair f t) = \b -> if b then t else f
from f = Pair (f False) (f True)