是否可以在Haskell中执行嵌套的if语句?

时间:2017-10-16 16:13:34

标签: haskell if-statement

我正在尝试对列表中的3个元素进行排序。但是我在将其翻译成haskell时遇到了麻烦。是否有可能在haskell中执行嵌套if语句?我一直在尝试模式匹配,但它永远带我。

if (x < y) {
    if (z < x) swap(x,z);
} else {
   if (y < z) swap(x,y);
else swap(x,z);
} 
  if(z<y) swap(y,z);

这就是我试过的

intCMP :: Int -> Int -> Ordering
intCMP a b | a == b =EQ
           | a < b = LT
           | otherwise = GT

sort3 :: Ord a => (a -> a -> Ordering) -> [a] -> [a]
sort3 cmp [a,b,c] = if cmp a b == LT then
                   if cmp a c == Lt then
                      if cmp b c == LT then
                         [a,b,c]
                      else
                         [a,c,b]
                   else
                      [c,a,b]
                else if cmp b c == LT then
                        if cmp a c == LT then
                             [b,a,c]
                        else
                             [b,c,a]
                else
                     [c,b,a]

3 个答案:

答案 0 :(得分:8)

这个技巧是在Haskell中if不是一个语句,而是一个表达式。它从其中一个分支返回一个值,而不是在那里执行代码。实际上,if可能只是函数if :: Bool -> a -> a -> a 的语法糖(当然,不存在这样的函数,因为if是一个关键字;仍然,一个人可以轻而易举地实现这样一个函数,如果命名不同,like this

所以,是的,嵌套的if语句是可能的,就像任何表达式一样,如

max x y z = if x < y then (if y < z then z else y) else (if x < z then z else x)

但是,这并不直接适用于您的情况,因为您无法轻松地执行swap:所有值在Haskell中都是不可变的。所以,如果你不想使用monad或类似的东西,解决方案可能是返回排序列表:

sort [x,y,z] =
    if x < y then
        (if y < z then
            [x,y,z]
        else
            (if x < z then
                [x,z,y]
                    else
                [z,x,y]
            )
        )
    else
        undefined -- implement other cases here

答案 1 :(得分:7)

正如lisyarus所说,你可以做到这一点。但是,if在Haskell中通常有点尴尬;通常,模式匹配是一个更好的选择 - 这可以避免布尔瓶颈,并允许您直接解构有意义的值。在您的情况下,最明显的事情是用== LT表达式替换丑陋的case检查:

sort3 cmp [a,b,c] = case cmp a b of
      LT -> case cmp a c of
         LT -> ...

因为你总是检查所有三个,但是没有必要嵌套检查;你不妨一次检查一下:

sort3 cmp [a,b,c] = case (cmp a b, cmp a c, cmp b c) of
       (GT, _ , GT) -> [c,b,a]
       (GT, LT, _ ) -> [b,a,c]
       (_ , LT, GT) -> [a,c,b]
       (_ , GT, _ ) -> [c,a,b]
       (GT, _ , _ ) -> [b,c,a]
       _            -> [a,b,c]

答案 2 :(得分:0)

对于三个元素,它并不重要,但是一旦你达到四个,那么交换的概念确实很有帮助,尽管我不会选择你的交换机制。你可以通过给每个计算阶段赋予它自己的功能来做到这一点。

>>> session = requests.Session()
>>> response = session.request('GET', 'http://httpbin.org/cookies/set?foo=bar')
>>> session.cookies  # no policy, so cookie got set
<RequestsCookieJar[Cookie(version=0, name='foo', value='bar', port=None, port_specified=False, domain='httpbin.org', domain_specified=False, domain_initial_dot=False, path='/', path_specified=True, secure=False, expires=None, discard=True, comment=None, comment_url=None, rest={}, rfc2109=False)]>
>>> session.cookies.clear()  # clean slate, no cookies
>>> session.cookies
<RequestsCookieJar[]>
>>> session.cookies.set_policy(BlockAll())
>>> response = session.request('GET', 'http://httpbin.org/cookies/set?foo=bar')
>>> session.cookies  # with policy, cookies still empty
<RequestsCookieJar[]>