在haskell中,如何将不带do符号定义的函数转为带do定义的函数?
In haskell, how to transfer the functions defined without do notation to the function defined with do?
我是 Haskell 的新人。现在我有一些关于类型的问题。
据说函数:
fg a tb tc = case lookup a tb of
Nothing -> Nothing
Just b -> case lookup b tc of
Nothing -> Nothing
Just c -> Just [b,c]
与函数相同:
fg' a tb tc = do
b <- lookup a tb
c <- lookup b tc
Just [b,c]
它们的类型都是 fg :: (Eq t, Eq a) => a -> [(a, t)] -> [(t, t)] -> Maybe [t]
但是,下面的函数被视为不同的函数:
fg'' a tb tc = do
let
b = lookup a tb
c = lookup b tc
Just [b,c]
它的类型是 fg'':: (Eq b, Eq a) => a -> [(a, b)] -> [(Maybe b, b)] -> Maybe [Maybe b]。
这些让我很困惑。谁能解释一下为什么?
你说的是 b = lookup a tb
。这意味着 b
与 lookup a tb
和 lookup :: Eq a => a -> [(a, b)] -> Maybe b
具有相同的类型。所以b :: Maybe b
。接下来,c = lookup b tc
表示 c
与 lookup b tc
具有相同的类型。因为 b :: Maybe b
、lookup b :: [(Maybe b, c)] -> Maybe c
(记住选择的类型变量是无关紧要的,只要它们是一致的)和 c :: Maybe c
。由于 Haskell 中的列表是同类的,[b, c]
意味着 b
和 c
具有相同的类型,因此 Maybe b ~ Maybe c
意味着 b ~ c
。由于 fg''
returns 的值为 Just [b, c]
,这意味着 Just [b, c] :: Maybe [Maybe b]
.
Haskell 中的 <-
语法不等同于 let
中的 =
。在您的情况下, fg'
可以使用 >>=
运算符在没有 do
的情况下转换为函数,对于 Maybe
具有类型
(>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
并且可以用作
fg''' a tb tc =
lookup a tb >>= (\b -> -- b <- lookup a tb
lookup b tc >>= (\c -> -- c <- lookup b tc
Just [b, c] -- Just [b, c]
)
)
将 >>=
视为将包装在 monad 中的值转发到 returns 一个新的 monadic 值的函数中。对于 Maybe
,如果 Maybe a
结果为 Nothing
,此运算符将短路,因为它没有值可前馈到 (a -> Maybe b)
。
monad 法则确保
do x <- return y -- note the return here
...
等同于
do let x = y
...
但是请注意,如果没有上面的return
,上面代码中的两个x
是不同的类型,所以它们永远不可能等价。这是因为如果y :: m a
,那么第一段代码有x :: a
,而第二段代码使用x :: m a
,而a
和m a
总是不同的类型。
例如,
do x <- [1]
return x
计算结果为 [1]
。相反,
do let x = [1]
return x
计算为 [[1]]
。
在 do
表示法中,<-
从 Monad
中取出值(在本例中为 Maybe
),让您在代码中操作该值如下。
但这不是它所做的唯一事情。
它还应用了相关 Monad
的 'characteristic'。 maybe的特点是,如果箭头右边的值为Nothing
,它不做任何解包(因为没有什么可解包的),只是整个计算失败,所以结果整个事情也是 Nothing
.
let
绑定不会做那样的事情。它只是为一些现有值分配一个新名称,因此当您执行 let a = lookup b tb
时,a
仍然是 Maybe something
类型。另一方面,当你像 a <- lookup b tb
这样解包时,a
的类型是 something
.
我是 Haskell 的新人。现在我有一些关于类型的问题。 据说函数:
fg a tb tc = case lookup a tb of
Nothing -> Nothing
Just b -> case lookup b tc of
Nothing -> Nothing
Just c -> Just [b,c]
与函数相同:
fg' a tb tc = do
b <- lookup a tb
c <- lookup b tc
Just [b,c]
它们的类型都是 fg :: (Eq t, Eq a) => a -> [(a, t)] -> [(t, t)] -> Maybe [t]
但是,下面的函数被视为不同的函数:
fg'' a tb tc = do
let
b = lookup a tb
c = lookup b tc
Just [b,c]
它的类型是 fg'':: (Eq b, Eq a) => a -> [(a, b)] -> [(Maybe b, b)] -> Maybe [Maybe b]。 这些让我很困惑。谁能解释一下为什么?
你说的是 b = lookup a tb
。这意味着 b
与 lookup a tb
和 lookup :: Eq a => a -> [(a, b)] -> Maybe b
具有相同的类型。所以b :: Maybe b
。接下来,c = lookup b tc
表示 c
与 lookup b tc
具有相同的类型。因为 b :: Maybe b
、lookup b :: [(Maybe b, c)] -> Maybe c
(记住选择的类型变量是无关紧要的,只要它们是一致的)和 c :: Maybe c
。由于 Haskell 中的列表是同类的,[b, c]
意味着 b
和 c
具有相同的类型,因此 Maybe b ~ Maybe c
意味着 b ~ c
。由于 fg''
returns 的值为 Just [b, c]
,这意味着 Just [b, c] :: Maybe [Maybe b]
.
Haskell 中的 <-
语法不等同于 let
中的 =
。在您的情况下, fg'
可以使用 >>=
运算符在没有 do
的情况下转换为函数,对于 Maybe
具有类型
(>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
并且可以用作
fg''' a tb tc =
lookup a tb >>= (\b -> -- b <- lookup a tb
lookup b tc >>= (\c -> -- c <- lookup b tc
Just [b, c] -- Just [b, c]
)
)
将 >>=
视为将包装在 monad 中的值转发到 returns 一个新的 monadic 值的函数中。对于 Maybe
,如果 Maybe a
结果为 Nothing
,此运算符将短路,因为它没有值可前馈到 (a -> Maybe b)
。
monad 法则确保
do x <- return y -- note the return here
...
等同于
do let x = y
...
但是请注意,如果没有上面的return
,上面代码中的两个x
是不同的类型,所以它们永远不可能等价。这是因为如果y :: m a
,那么第一段代码有x :: a
,而第二段代码使用x :: m a
,而a
和m a
总是不同的类型。
例如,
do x <- [1]
return x
计算结果为 [1]
。相反,
do let x = [1]
return x
计算为 [[1]]
。
在 do
表示法中,<-
从 Monad
中取出值(在本例中为 Maybe
),让您在代码中操作该值如下。
但这不是它所做的唯一事情。
它还应用了相关 Monad
的 'characteristic'。 maybe的特点是,如果箭头右边的值为Nothing
,它不做任何解包(因为没有什么可解包的),只是整个计算失败,所以结果整个事情也是 Nothing
.
let
绑定不会做那样的事情。它只是为一些现有值分配一个新名称,因此当您执行 let a = lookup b tb
时,a
仍然是 Maybe something
类型。另一方面,当你像 a <- lookup b tb
这样解包时,a
的类型是 something
.