此 'where' 子句的正确 Haskell 语法是什么?

what is the correct Haskell syntax for this 'where' clause?

此语法的适当更正是什么?是白space的问题吗?我复制了 LYAH, also tried other variations gleaned from .

中示例中使用的 whitespace

我确定有更好的方法来编写此代码,但我还不太擅长自由代码。我是 新手 级别,正在尝试掌握非常基本的语法知识,这些语法知识通过大量的 codewars 练习继续让我感到困惑。

import Data.List (findIndices)

basicOp :: Char -> Int -> Int -> Int
basicOp x y z = (operations  !! (op x)) y z
    where op x = head $ findIndices (== x) "+-*/" :: Char -> Int
    operations = [(+), (-), (*), (div)]  :: [(Int -> Int -> Int)]

当我像这样写一个函数并引用另外两个函数时它起作用了。

import Data.List (findIndices)

operations :: [(Int -> Int -> Int)]
operations = [(+), (-), (*), (div)]

op :: Char -> Int
op x = head $ findIndices (== x) "+-*/" 

basicOp :: Char -> Int -> Int -> Int
basicOp x y z = (operations  !! (op x)) y z

带有 where 子句的代码 returns 这些错误:

codewars.hs:103:34: error:
    • Couldn't match expected type ‘Int’ with actual type ‘Char -> Int’
    • Probable cause: ‘op’ is applied to too few arguments
      In the second argument of ‘(!!)’, namely ‘(op x)’
      In the expression: (operations !! (op x)) y z
      In an equation for ‘basicOp’:
          basicOp x y z
            = (operations !! (op x)) y z
            where
                op x = head $ findIndices (== x) "+-*/" :: Char -> Int
                operations = [(+), ....] :: [(Int -> Int -> Int)]
    |
103 | basicOp x y z = (operations  !! (op x)) y z
    |                                  ^^^^

codewars.hs:104:18: error:
    • Couldn't match expected type ‘Char -> Int’ with actual type ‘Int’
    • Possible cause: ‘($)’ is applied to too many arguments
      In the expression: head $ findIndices (== x) "+-*/" :: Char -> Int
      In an equation for ‘op’:
          op x = head $ findIndices (== x) "+-*/" :: Char -> Int
      In an equation for ‘basicOp’:
          basicOp x y z
            = (operations !! (op x)) y z
            where
                op x = head $ findIndices (== x) "+-*/" :: Char -> Int
                operations = [(+), ....] :: [(Int -> Int -> Int)]
    |
104 |     where op x = head $ findIndices (== x) "+-*/" :: Char -> Int
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

我最初的尝试可能更容易阅读,但这只是一个尝试使用更多我还不熟悉的 Haskell 结构的练习。

basicOp :: Char -> Int -> Int -> Int
basicOp oper x y
    | oper == '+'  = (+)   x y 
    | oper == '-'  = (-)   x y
    | oper == '*'  = (*)   x y
    | oper == '/'  = (div) x y

根据@DanielWagner 的评论,这已改进为:

basicOp c = case c of
    '+' -> (+)
    '-' -> (-)
    '*' -> (*)
    '/' -> div

op x 表达式的主体类型是 Int,而不是 Char -> Int。您还应该将 operationsop 放在同一列,因此:

basicOp :: Char -> Int -> Int -> Int
basicOp x y z = (operations  !! (op x)) y z
    where op x = head $ findIndices (== x) "+-*/" :: Int
          operations = [(+), (-), (*), (div)]  :: [(Int -> Int -> Int)]

但是类型不是必须的,你可以简化为:

basicOp :: Char -> Int -> Int -> Int
basicOp x = (operations  !! op x)
    where op x = head $ findIndices (== x) "+-*/"
          operations = [(+), (-), (*), (div)]

并与 lookup :: Eq a => a -> [(a, b)] -> Maybe b 一起工作:

basicOp :: Char -> Int -> Int -> Int
basicOp x | Just y <- lookup x operations = y
          | otherwise = …
    where operations = [('+', (+)), ('-', (-)), ('*', (*)), ('/', div)]

其中 是一个表达式,如果未找到该键,则对其求值

哦,删除 opoperations 的类型声明有效。

我认为有时将类型声明“内联”是可以的(甚至有帮助)。

basicOp :: Char -> Int -> Int -> Int
basicOp x y z = (operations  !! (op x)) y z
    where 
        op x = head $ findIndices (== x) "+-*/" 
        operations = [(+), (-), (*), (div)]  

请注意,您可以为函数本身提供类型,或者在单独的行上

basicOp :: Char -> Int -> Int -> Int
basicOp x y z = (operations  !! (op x)) y z
    where
        op :: Char -> Int
        op x = head $ findIndices (== x) "+-*/"
        operations = [(+), (-), (*), (div)]  :: [(Int -> Int -> Int)]

或通过提供明确的 lambda 表达式作为 op.

的值
basicOp :: Char -> Int -> Int -> Int
basicOp x y z = (operations  !! (op x)) y z
    where op = (\x -> head $ findIndices (== x) "+-*/") :: Char -> Int
          operations = [(+), (-), (*), (div)]  :: [(Int -> Int -> Int)]