haskell、monad、绑定的定义以及输出值上的奇怪模式匹配?
haskell, monad, definition of bind, and weird pattern matching on an output value?
下面是来自 another stack overflow question 答案的一些代码。我已经开始研究 Haskell 好几个星期了,但我还没有遇到这种特殊的语法,而且我找不到任何解释,甚至连定义都找不到。
所以,代码:
data Pair a = P a a
instance Functor Pair where
fmap f (P x y) = P (f x) (f y)
instance Monad Pair where
return x = P x x
P a b >>= f = P x y
where P x _ = f a
P _ y = f b
我花了最后 half-hour 试图理解它的含义,或者如果我已经知道的东西解释了这个绑定 (>>=) 方法的定义。 GHCI 毫不费力地加载了它(好吧,它需要一个 Applicative 实例,但除此之外),所以它必须是非常允许的,即使我还没有理解它的开头。
看起来像 pattern-matching 定义的已定义数据构造函数的含义是什么? x和y是什么,它们从哪里来?
感谢所有回答此问题的人。如果有人对这个问题有一个好的、具体的标题的好主意——鉴于我真的不明白语法的含义,我很难找到一个。
@leftaroundabout 给了我需要的信息,就是那段代码
P x y
where P x _ = f a
P _ y = f b
是 "value-unboxing" 类型的 pattern-matching 的一种形式,而不是类似于 case of
的 choice-oriented 类型。我对 _
模式的存在感到困惑,因此我没有看到上面两个 pattern-matching 的原样,即 x
然后 [= 的定义19=], 因为它是以我以前从未见过的方式完成的。
我知道我们可以这样写:
f :: foo -> (Int, Int)
...
i = let (a,b) = f x
in a + b
但我不知道我们可以在 "value-unboxing" 的这些情况下使用(例如这里 a
和 b
,或者 x
和 y
在困扰我的代码中),pattern-matching 中可能性的全部范围,也就是说,至少,定义使用 _
来隔离我们不想要的部分,我们不想要的值'不想绑定到任何 "label".
总之我不知道在上面的例子中,这个等式
P x _ = f a
实际上是 x
到 pattern-matching 在 (f a)
的结果上的定义,因此它在效果上严格等同于
x = g (f a)
where g (P t _) = t
我一直以为这是 already-defined 数据构造函数的定义 P
。
这里没有“特定语法”,只是一个普通的模式匹配。代码相当于
pFst, pSnd :: Pair a -> a
pFst (Pair x _) = x
pSnd (Pair _ y) = y
instance Monad Pair where
return x = P x x
P a b >>= f = P x y
where x = pFst $ f a
y = pSnd $ f b
如果您内联 pFst
和 pSnd
,您会发现这直接导致原始定义。
如果您不信服,请考虑(非递归)where
绑定可以替换为 lambda 抽象:
P a b >>= f = (\(Pair x _) (Pair _ y) -> P x y)
(f a) (f b)
显然,lambda 也可以写成命名的局部函数:
P a b >>= f = pFstAndPSnd (f a) (f b)
where pFstAndPSnd (Pair x _) (Pair _ y) = P x y
如果您看到了寻找普通元组的代码,也许就不会那么混乱了:
(>>=) :: (c,c) -> (c -> (d,d)) -> (d,d)
(a,b) >>= f = (x,y)
where (x,_) = f a
(_,y) = f b
这 显然† 没有以任何方式重新定义 (,)
构造函数,只是用它来进行模式匹配函数的元组结果。
†好吧,好吧,也许 不那么明显,因为你也可以做类似 let 1+2=4 in 1+2
,得到4
作为结果。
嗯 P
确实是 Pair
的构造函数所以 a
和 b
将是这个的第一个和第二个元素(有点奇怪) pair(如果你说 x = P 1 2
然后做 x >>= f
那么这里 a = 1
和 b = 2
- 这正是 模式匹配
我猜你在定义函数时遇到了问题。如果有帮助你可以写成:
(>>=) (P a b) f = P x y
where ...
也是
请参阅:正如您可以在参数之间使用运算符一样,您可以在那里定义它吗
下面是来自 another stack overflow question 答案的一些代码。我已经开始研究 Haskell 好几个星期了,但我还没有遇到这种特殊的语法,而且我找不到任何解释,甚至连定义都找不到。 所以,代码:
data Pair a = P a a
instance Functor Pair where
fmap f (P x y) = P (f x) (f y)
instance Monad Pair where
return x = P x x
P a b >>= f = P x y
where P x _ = f a
P _ y = f b
我花了最后 half-hour 试图理解它的含义,或者如果我已经知道的东西解释了这个绑定 (>>=) 方法的定义。 GHCI 毫不费力地加载了它(好吧,它需要一个 Applicative 实例,但除此之外),所以它必须是非常允许的,即使我还没有理解它的开头。
看起来像 pattern-matching 定义的已定义数据构造函数的含义是什么? x和y是什么,它们从哪里来?
感谢所有回答此问题的人。如果有人对这个问题有一个好的、具体的标题的好主意——鉴于我真的不明白语法的含义,我很难找到一个。
@leftaroundabout 给了我需要的信息,就是那段代码
P x y
where P x _ = f a
P _ y = f b
是 "value-unboxing" 类型的 pattern-matching 的一种形式,而不是类似于 case of
的 choice-oriented 类型。我对 _
模式的存在感到困惑,因此我没有看到上面两个 pattern-matching 的原样,即 x
然后 [= 的定义19=], 因为它是以我以前从未见过的方式完成的。
我知道我们可以这样写:
f :: foo -> (Int, Int)
...
i = let (a,b) = f x
in a + b
但我不知道我们可以在 "value-unboxing" 的这些情况下使用(例如这里 a
和 b
,或者 x
和 y
在困扰我的代码中),pattern-matching 中可能性的全部范围,也就是说,至少,定义使用 _
来隔离我们不想要的部分,我们不想要的值'不想绑定到任何 "label".
总之我不知道在上面的例子中,这个等式
P x _ = f a
实际上是 x
到 pattern-matching 在 (f a)
的结果上的定义,因此它在效果上严格等同于
x = g (f a)
where g (P t _) = t
我一直以为这是 already-defined 数据构造函数的定义 P
。
这里没有“特定语法”,只是一个普通的模式匹配。代码相当于
pFst, pSnd :: Pair a -> a
pFst (Pair x _) = x
pSnd (Pair _ y) = y
instance Monad Pair where
return x = P x x
P a b >>= f = P x y
where x = pFst $ f a
y = pSnd $ f b
如果您内联 pFst
和 pSnd
,您会发现这直接导致原始定义。
如果您不信服,请考虑(非递归)where
绑定可以替换为 lambda 抽象:
P a b >>= f = (\(Pair x _) (Pair _ y) -> P x y)
(f a) (f b)
显然,lambda 也可以写成命名的局部函数:
P a b >>= f = pFstAndPSnd (f a) (f b)
where pFstAndPSnd (Pair x _) (Pair _ y) = P x y
如果您看到了寻找普通元组的代码,也许就不会那么混乱了:
(>>=) :: (c,c) -> (c -> (d,d)) -> (d,d)
(a,b) >>= f = (x,y)
where (x,_) = f a
(_,y) = f b
这 显然† 没有以任何方式重新定义 (,)
构造函数,只是用它来进行模式匹配函数的元组结果。
†好吧,好吧,也许 不那么明显,因为你也可以做类似 let 1+2=4 in 1+2
,得到4
作为结果。
嗯 P
确实是 Pair
的构造函数所以 a
和 b
将是这个的第一个和第二个元素(有点奇怪) pair(如果你说 x = P 1 2
然后做 x >>= f
那么这里 a = 1
和 b = 2
- 这正是 模式匹配
我猜你在定义函数时遇到了问题。如果有帮助你可以写成:
(>>=) (P a b) f = P x y
where ...
也是
请参阅:正如您可以在参数之间使用运算符一样,您可以在那里定义它吗