我可能一直错误地认为 Haskell 比现在更懒惰,但我想知道是否有办法两全其美……
Data.Monoid并Data.Semigroup定义 的两个变体First。幺半群版本对最左边的非空值建模,而半群版本只是对最左边的值建模。
这适用于纯值,但考虑不纯值:
x = putStrLn "x" >> return 42
y = putStrLn "y" >> return 1337
Run Code Online (Sandbox Code Playgroud)
这两个值都具有类型Num a => IO a。IO a是一个Semigroup实例,当a是:
instance Semigroup a => Semigroup (IO a)
-- Defined in `Data.Orphans'
Run Code Online (Sandbox Code Playgroud)
这意味着可以组合两个IO (First a)值:
Prelude Data.Semigroup Data.Orphans> fmap First x <> fmap First y
x
y
First {getFirst = 42}
Run Code Online (Sandbox Code Playgroud)
我们可以看到,虽然双方x并y产生各自的副作用,即使y是从来没有要求。
这同样适用于Data.Monoid …
这是我上一个问题的后续内容
Kleisli定义了两个运算符<=<(compose)和>=>(andThen).在>=>找我很自然的,我不明白怎么<=<会很有用.
而且,看起来没有>=>半群,A => M[A]但是<=<半群确实存在.
它背后的理由是什么?
使用cats.Semigroup可以这样写:
import cats.Semigroup
import cats.implicits._
val l1: String Either Int = Left("error")
val r1: String Either Int = Right(1)
val r2: String Either Int = Right(2)
l1 |+| r1 // Left("error")
r1 |+| r2 // Right(3)
Run Code Online (Sandbox Code Playgroud)
我希望有一个同样惯用的运算符(类似combine),其工作方式如下:
Right我的计算中至少有一个,则返回一个RightLeft,则返回一个Left例如:
Right(1) |+| Right(2) // Right(3)
Right(1) |+| Left("2") // Right(1)
Left("1") |+| Left("2") // Left("12") // in my particular case the wrapped value here does not really matter (could also be …Run Code Online (Sandbox Code Playgroud) 我正在 Haskell 库中寻找如下所示的类(或者至少知道此类事物的数学名称):
class Monoid patch => MyThing patch t where
applyPatch :: t -> patch -> t
Run Code Online (Sandbox Code Playgroud)
我可以有这样的实例:
instance MyThing (Last t) t where
applyPatch x patch = case getLast patch of
Just y => y
Nothing => x
Run Code Online (Sandbox Code Playgroud)
但我也可以有这样的实例:
instance MyThing (Dual (Map key value)) (Map key value) where
applyPatch x patch = ...
Run Code Online (Sandbox Code Playgroud)
补丁本质上是添加和/或替换映射中的键/值对。
如果你想删除,可以更进一步:
instance MyThing (Dual (Map key (Maybe value))) (Map key value) where
applyPatch x patch = ...
Run Code Online (Sandbox Code Playgroud)
除了patch成为幺半群之外,我希望此类遵循的主要法则是结合性,具体来说:
forall (x :: …Run Code Online (Sandbox Code Playgroud) 我正在尝试制作一个井字游戏,我决定构建单元格(板的元素)和板的类型如下:
data Cell = X | O deriving (Show, Eq)
type Board = [[Maybe Cell]]
Run Code Online (Sandbox Code Playgroud)
这里,Nothing表示空单元格(Just X)和(Just O)分别表示用X和O填充的单元格.
我想将(Maybe Cell)定义为monoid,如下所示:
instance Monoid (Maybe Cell) where
mempty = Nothing
mappend Nothing x = x
mappend (Just x) _ = (Just x)
Run Code Online (Sandbox Code Playgroud)
和董事会作为另一个幺半群
instance Monoid Board where
mempty = [[Nothing, Nothing, Nothing]
,[Nothing, Nothing, Nothing]
,[Nothing, Nothing, Nothing]]
mappend = zipWith (zipWith mappend)
-- where the right-hand-side mappend is the addition on (Maybe Cell)
Run Code Online (Sandbox Code Playgroud)
我知道我可以在没有幺半群的情况下完全实现这一点,但我正在尝试探索这个领域,而这只是一种非常巧妙的方式来编写它.
我得到的问题是Maybemonoid实例已经定义GHC.Base如下:
instance Semigroup …Run Code Online (Sandbox Code Playgroud) 让我们看看 Haskell 中用于处理反向列表的新数据类型的声明:
import Data.Monoid
data RevList a = Nil | RCons (RevList a) a deriving (Eq, Show)
instance Monoid a => Monoid (RevList a) where
mempty = Nil
instance Semigroup a => Monoid (RevList a) where
Nil <> RCons (RevList a) a = RCons (RevList a) a
RCons (RevList a) a <> RNil = RCons (RevList a) a
Nil <> Nil = Nil
Run Code Online (Sandbox Code Playgroud)
我困扰的问题是编译失败,其描述如下:
`<>' is not a (visible) method of class `Monoid'
Run Code Online (Sandbox Code Playgroud)
首先,我尝试在没有任何 Semigroup 实例声明的情况下创建一个 Monoid 实例,但是在阅读此问题 …
我想实现一个名为 ComplexNumber 的自定义数据类型,如下所示:
data ComplexNumber a = C (a,a)
现在我想实现 Monoid 变量并定义二进制 mempty 元素和 mappend,如下所示:
instance Num a => Monoid (ComplexNumber a) where
mempty = C (0,0)
mappend = (C (a1, b1)) (C (a2, b2)) = C (a1 + a2, b1 + b2)
Run Code Online (Sandbox Code Playgroud)
但这没有成功,所以试图找出原因并遇到了 Semigroup (我仍然不太理解)并找到了一个至少可以编译并且似乎可以使用的解决方案:
instance Num a => Semigroup (ComplexNumber a) where
(C (a1, b1)) <> (C (a2,b2)) = C (a1 + a2, b1 + b2)
instance Num a => Monoid (ComplexNumber a) where
mempty = C (0,0) …Run Code Online (Sandbox Code Playgroud) 我有以下数据类型和半群实例:
data Or a b =
Fst a
| Snd b deriving (Eq, Show)
instance Semigroup (Or a b) where
(<>) (Fst a) (Fst b) = Fst b
(<>) (Snd a) (Fst b) = Snd a
(<>) (Fst a) (Snd b) = Snd b
(<>) (Snd a) (Snd b) = Snd a
Run Code Online (Sandbox Code Playgroud)
我想为上面的类型创建一个monoid实例,但我不知道如何做到这一点.如果我使用以下定义
instance (Monoid a, Monoid b) => Monoid (Or a b) where
mempty = (Fst mempty)
mappend = (<>)
Run Code Online (Sandbox Code Playgroud)
<>除了I之外,它将适用于所有输入对mappend
(Fst a) <> mempty
Run Code Online (Sandbox Code Playgroud)
将评估为mempty …