在haskell中,如何将没有用符号定义的函数传递给用do定义的函数?

时间:2015-01-13 22:10:31

标签: haskell types

我是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)=&gt; a - &gt; [(a,t)] - &gt; [(t,t)] - &gt;也许[t]

但是,以下功能被视为不同的功能:

fg'' a tb tc = do
    let     
        b = lookup a tb
        c = lookup b tc
    Just [b,c]

它的类型是fg''::(Eq b,Eq a)=&gt; a - &gt; [(a,b)] - &gt; [(可能b,b)] - &gt;也许[也许b]。 这些让我困惑。有人能解释原因吗?

3 个答案:

答案 0 :(得分:3)

你说b = lookup a tb。这意味着blookup a tblookup :: Eq a => a -> [(a, b)] -> Maybe b具有相同的类型。所以b :: Maybe b。接下来,c = lookup b tc表示clookup b tc的类型相同。自b :: Maybe blookup b :: [(Maybe b, c)] -> Maybe c以来(请记住所选的类型变量无关紧要,只要它们一致),c :: Maybe c。由于Haskell中的列表是同构的,[b, c]表示bc具有相同的类型,因此Maybe b ~ Maybe c隐含b ~ c。由于fg''返回的值为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中的值转换为返回新monadic值的函数。对于Maybe,如果Maybe a原来是Nothing,则此运算符会短路,因为它不会有值向前馈入(a -> Maybe b)

答案 1 :(得分:3)

monad法律确保

do x <- return y   -- note the return here
   ...

相当于

do let x = y
   ...

但请注意,如果没有上面的return,上面代码中的两个x具有不同的类型,因此它们永远不会是等价的。这是因为如果y :: m a,则第一段代码为x :: a,而第二段使用x :: m aam a始终为不同类型。

例如,

do x <- [1]
   return x

评估为[1]。取而代之的是,

do let x = [1]
   return x

评估为[[1]]

答案 2 :(得分:1)

do表示法中,<-取值Monad(在这种情况下为Maybe)并让您操纵该值随后的代码。 但这不是唯一的事情。

它也适用于&#39;特征&#39;有问题的Monad。可能的特征是,如果箭头右侧的值为Nothing,则它不会进行任何展开(因为没有任何东西要打开)并且只是无法进行整个计算,所以整件事的结果也是Nothing

let绑定不会做那样的事情。它只是为某个现有值指定了新名称,因此当您执行let a = lookup b tb时,a仍然属于Maybe something类型。另一方面,当您像a <- lookup b tb一样打开它时,a的类型为something