理解单子函数组合
Understanding monadic function composition
我正在从 Miran Lipovaca 的 'Learn You a Haskell for Great Good!' 一书中学习单子。我试图了解单子的结合律。从本质上讲,法律规定当你有一个带有 >>=
的 monadic 函数应用程序链时,它们的嵌套方式无关紧要。
以下代码可以将 a -> m b
类型函数的结果传递给 b -> m c
类型函数:
(<=<) :: (Monad m) => (b -> m c) -> (a -> m b) -> (a -> m c)
f <=< g = (\x -> g x >>= f)
但是,对于下面的示例:
ghci> let f x = [x, -x]
ghci> let g x = [x*3, x*2]
ghci> let h = f <=< g
ghci> h 3
[9, -9, 6, -6]
f x
和g x
都是函数吗?似乎它们是具有不同 x 值而不是函数的列表。 let h = f <=< g
行在上面的代码中是如何工作的? f
和 g
必须是函数,因为它们与 <=<
一起使用,但我不确定它们是什么。
f x = [x, -x]
这是普通的函数定义语法。我们正在 定义 一个新函数 f
,写下它在应用于假设值 x
.
时会产生什么
let
(无论是作为语句还是 let ... in ...
表达式)只是引入一个块,您可以在其中进行定义,很像 where
。定义本身使用与全局定义相同的语法。
如果您知道如何通过编写例如plusOne n = n + 1
在一个文件中,那么这个语法是完全一样的(如果你不知道该怎么做,那么我建议你在尝试之前阅读一些关于基础 Haskell 语法的入门教程了解 monadic 函数组合)。
所以在这些定义之后 f
和 g
是函数。 f x
和 g x
没有任何意义,因为您没有 x
范围来应用它们。
如果您在范围内确实有这样的值,那么 f x
将是一个计算结果为列表的表达式,其中涉及 调用 函数 f
.说 f x
或 g x
是函数仍然是不正确的。
所以现在应该清楚 let h = f <=< g
通过将 <=<
运算符应用于 f
和 g
来定义新值 h
。
没有什么比在 sheet 纸上手写定义更好的了。
f x = [x, -x]
也可以写成f = (\ x -> [x, -x])
。因此
h 3
= {- by def of h -}
(f <=< g) 3
= {- by def of (<=<) -}
(\x -> g x >>= f ) 3
= {- by defs of f and g -}
(\x -> (\ x -> [x*3, x*2]) x >>= (\ x -> [x, -x])) 3
= {- by substitution -}
(\ x -> [x*3, x*2]) 3 >>= (\ x -> [x, -x])
= {- by substitution -}
[3*3,
3*2] >>= (\ x -> [x, -x])
= {- by definition of (>>=) for [] -}
concat [ (3*3) & (\ x -> [x, -x]) -- x & f == f x
, (3*2) & (\ x -> [x, -x])
]
= {- by definition of concat -}
(3*3) & (\ x -> [x, -x])
++ (3*2) & (\ x -> [x, -x])
=
[9, -9, 6, -6]
(edit) 有关这些 Kleisli 箭头 及其可组合性的图片和更多讨论,请参阅 this older answer of mine .
我正在从 Miran Lipovaca 的 'Learn You a Haskell for Great Good!' 一书中学习单子。我试图了解单子的结合律。从本质上讲,法律规定当你有一个带有 >>=
的 monadic 函数应用程序链时,它们的嵌套方式无关紧要。
以下代码可以将 a -> m b
类型函数的结果传递给 b -> m c
类型函数:
(<=<) :: (Monad m) => (b -> m c) -> (a -> m b) -> (a -> m c)
f <=< g = (\x -> g x >>= f)
但是,对于下面的示例:
ghci> let f x = [x, -x]
ghci> let g x = [x*3, x*2]
ghci> let h = f <=< g
ghci> h 3
[9, -9, 6, -6]
f x
和g x
都是函数吗?似乎它们是具有不同 x 值而不是函数的列表。 let h = f <=< g
行在上面的代码中是如何工作的? f
和 g
必须是函数,因为它们与 <=<
一起使用,但我不确定它们是什么。
f x = [x, -x]
这是普通的函数定义语法。我们正在 定义 一个新函数 f
,写下它在应用于假设值 x
.
let
(无论是作为语句还是 let ... in ...
表达式)只是引入一个块,您可以在其中进行定义,很像 where
。定义本身使用与全局定义相同的语法。
如果您知道如何通过编写例如plusOne n = n + 1
在一个文件中,那么这个语法是完全一样的(如果你不知道该怎么做,那么我建议你在尝试之前阅读一些关于基础 Haskell 语法的入门教程了解 monadic 函数组合)。
所以在这些定义之后 f
和 g
是函数。 f x
和 g x
没有任何意义,因为您没有 x
范围来应用它们。
如果您在范围内确实有这样的值,那么 f x
将是一个计算结果为列表的表达式,其中涉及 调用 函数 f
.说 f x
或 g x
是函数仍然是不正确的。
所以现在应该清楚 let h = f <=< g
通过将 <=<
运算符应用于 f
和 g
来定义新值 h
。
没有什么比在 sheet 纸上手写定义更好的了。
f x = [x, -x]
也可以写成f = (\ x -> [x, -x])
。因此
h 3
= {- by def of h -}
(f <=< g) 3
= {- by def of (<=<) -}
(\x -> g x >>= f ) 3
= {- by defs of f and g -}
(\x -> (\ x -> [x*3, x*2]) x >>= (\ x -> [x, -x])) 3
= {- by substitution -}
(\ x -> [x*3, x*2]) 3 >>= (\ x -> [x, -x])
= {- by substitution -}
[3*3,
3*2] >>= (\ x -> [x, -x])
= {- by definition of (>>=) for [] -}
concat [ (3*3) & (\ x -> [x, -x]) -- x & f == f x
, (3*2) & (\ x -> [x, -x])
]
= {- by definition of concat -}
(3*3) & (\ x -> [x, -x])
++ (3*2) & (\ x -> [x, -x])
=
[9, -9, 6, -6]
(edit) 有关这些 Kleisli 箭头 及其可组合性的图片和更多讨论,请参阅 this older answer of mine .