Haskell中的语句排序?

Haskell中的语句排序?,haskell,Haskell,我正在尝试编译一个非常简单的haskell程序。要么我不知道如何在Haskell中对语句(表达式)进行排序,要么就是没有办法做到这一点 我基本上想要一个函数的形式: f = <do stuff 1> <do stuff 2> ... 这也不起作用(更简单,没有递归): 上面的代码可以编译,但在运行时,我得到了一个神秘的信息: No instance for (Num (a0 -> t0)) arising from a use of `go'

我正在尝试编译一个非常简单的haskell程序。要么我不知道如何在Haskell中对语句(表达式)进行排序,要么就是没有办法做到这一点

我基本上想要一个函数的形式:

f = <do stuff 1>
    <do stuff 2>
    ...
这也不起作用(更简单,没有递归):

上面的代码可以编译,但在运行时,我得到了一个神秘的信息:

No instance for (Num (a0 -> t0))
  arising from a use of `go'
Possible fix: add an instance declaration for (Num (a0 -> t0))
In the expression: go 2
In an equation for `it': it = go 2
我在缩进方面有问题吗?排序不正确的问题?还是没有排序功能?如果没有排序,你会直接怎么做

<do stuff>
<tail recursion>
运行示例:

erlang> count([a,b,c,d,e],0).
5
第2条符合我前面描述的模式:

<do stuff>
<tail recursion>

我猜这个特定的例子映射到这里描述的Haskell“让……进来”的人。但如果需要10个“做事”,或20个或更多,该怎么办?这个“let…in”保证是尾部递归的(上面的例子保证是在erlang、prolog、scheme等中)


有没有一种方法可以简单地“串在一起”或“排序”一组语句或表达式?在prolog或erlang中,排序由逗号完成(参见上面的示例)。在c/c++中,它由分号完成。我以为Haskell运算符只是空白,但也许它不是用这种语言实现的?

基本上,没有办法实现。Haskell是一种纯粹的函数式语言,既没有变化,也没有语句顺序。模拟序列的一种方法是单子。互联网上有很多教程,我个人建议你阅读或的monad章节。另一件事是:顺序操作在Haskell中不是很惯用。你最好从不同的开始

我不确定你的函数做了什么。也许你需要这样的东西:

go :: Int -> Int
go 0 = 0
go i = go (i-1)
如果该函数接受参数,例如“3”,它将计算go 3->go 2->go 1->go 0->0并得到答案“0”

现在,如果你想要一些排序,你可以使用关键字'do',但我相信这是你现在需要的。如果您试图创建某种“变量”,请查看“let”和“in”语句:

someInput = 7

gogogo 0  = 0
gogogo n = 
    let
        gavk = n + 1
        kravk = gavk * 2
        out = kravk + 1
    in 
        out

main = 
   do
       putStrLn "this is sample do statement"
       putStrLn "gogogo:"
       putStrLn $ gogogo someInput 
UPD。当你说“做事”时,你是什么意思

  • 计算一些东西,转换我们已有的数据
  • 与用户交互,读/写文件,从网上下载东西
在第一种情况下,在中使用

quadraticRoots a b c = let discriminant = b * b - 4 * a * c
                           root = sqrt discriminant
                       in case compare discriminant 0 of
                               LT -> []
                               EQ -> [-b / (2 * a)]
                               GT -> [(-b + root) / (2 * a), (-b - root) / (2 * a)]
在第二种情况下,使用
do
表示法:

main = do args <- getArgs
          case map read args of
               [a, b, c] -> putStrLn $ case quadraticRoots a b c of
                                            [] -> "no real roots"
                                            [x] -> "single root: " ++ show x
                                            [x1, x2] -> unwords ["two real roots:", show x1,
                                                                 "and", show x2]
               _ -> hPutStrLn stderr "Please provide three coefficients on the command line"
main=do args putStrLn$case quarticroots a b c of
[]->“没有真正的根”
[x] ->“单根:”++显示x
[x1,x2]->UNWORD[“两个实根:”,显示x1,
“和”,显示x2]
_->hPutStrLn stderr“请在命令行上提供三个系数”

在Haskell中,您不会编写“做事情”的函数。您可以编写计算值的函数。在这种情况下,按照您建议的方式构造函数是没有意义的:

f = <do stuff 1>
    <do stuff 2>
将其分解为子表达式可能比较方便

f x y = res1 + res2
  where res1 = x * 3
        res2 = y + 4
但最终,它只是一个单一的表达


do
符号编写的一元代码可以按顺序显示为“do stuff”:

f = do
  thing1
  thing2
但这只是一种错觉。它也分解为一个表达式:

f = thing1 >> thing2

此表达式表示
f
是一个值,它是
thing1
thing2
的组成部分。现在,IO代码可能会编译成按顺序“做事情”的代码,但这不是Haskell中的意思。在哈斯克尔,人们不仅仅是“做事”。相反,您需要编写。

更新:请注意不要在Haskell中编写Scheme程序。累积参数在惯用的Haskell中很少见,它使用惰性而不是尾部递归

例如,Haskell中的
count
的定义类似于

count [] = 0
count (x:xs) = 1 + count xs
你可能会反对这个计划看起来更像一个计划

-- | /O(n)/. 'length' returns the length of a finite list as an 'Int'.
-- It is an instance of the more general 'Data.List.genericLength',
-- the result type of which may be any kind of number.
length                  :: [a] -> Int
length l                =  len l 0#
  where
    len :: [a] -> Int# -> Int
    len []     a# = I# a#
    len (_:xs) a# = len xs (a# +# 1#)
但这是低级的、非惯用的代码。所引用的结构与上面的
count
相同,并且与
长度
相比具有更广泛的适用性

genericLength           :: (Num i) => [b] -> i
genericLength []        =  0
genericLength (_:l)     =  1 + genericLength l
Haskell中的“先做这个,然后再做那个”在纯代码中表示为函数组合。例如,要计算最长子列表的长度,我们需要计算子列表的长度,然后计算这些长度上的最大值。在哈斯凯尔,这是表达出来的

Prelude> :t maximum . map length
maximum . map length :: [[a]] -> Int

注意:懒惰增加了细微差别,但总的观点是正确的

甚至在
IO
中的“命令式”代码中,例如

main :: IO ()
main = do
  putStr "Hello "
  purStrLn "world!"
函数组合是隐藏的,因为它与

main :: IO ()
main = putStr "Hello " >>= \_ -> putStrLn "world!"
也许一个使用列表单子的例子会使这一点更清楚。假设我们想要所有的毕达哥拉斯三元组
(a,b,c)
,这样就没有一个组分大于某个最大值n

在列表monad中,
>=
为,因此上述内容与

triples_stacked :: Integer -> [(Integer,Integer,Integer)]
triples_stacked n =
  concatMap (\a ->
    concatMap (\b ->
      concatMap (\c ->
        concatMap (\_ ->
          [(a,b,c)])
          (guard $ a*a + b*b == c*c))
        [b .. n])
      [a .. n])
    [1 .. n]
缩进显示出结构,令人愉悦,因为它给人的印象是结合了λ和
>>=
的Haskell徽标

另一种表达相同语义的方法是

triples_cm n = concatMap step2 [1 .. n]  -- step 1
  where step2 a = concatMap step3 [a .. n]
          where step3 b = concatMap step4 [b .. n]
                  where step4 c = concatMap step5 (guard $ a*a + b*b == c*c)
                          where step5 _ = [(a,b,c)]

Haskell的模式匹配已经在幕后进行了
case
匹配。而不是

go 0 = 0
go i =  case i of
            1 -> 2
            _ -> 3
        go (i-1)
完成你开始的模式

go 0 = 0
go 1 = go (2 - 1)
go _ = go (3 - 1)
请记住,Haskell中的变量是不可变的:它们没有C或Java中的破坏性更新。你只需要定义一个变量的值,然后你就被它卡住了。您可以将
go
定义为

go 0 = 0
go x = let i = case x of 1 -> 2
                         _ -> 3
       in go (i - 1)


上面的示例都是typecheck,但有相同的大问题,即
go
仅在其参数为零时终止。你没有提供足够的信息帮助我们解决这个问题。告诉我们你想做什么,我们可以针对你的情况提供具体的建议。

很好,你是一名
main :: IO ()
main = putStr "Hello " >>= \_ -> putStrLn "world!"
import Control.Monad (guard)

triples :: Integer -> [(Integer,Integer,Integer)]
triples n = do
  a <- [1 .. n]
  b <- [a .. n]
  c <- [b .. n]
  guard $ a*a + b*b == c*c
  return (a,b,c)
-- indented to show nested scopes
triples_bind :: Integer -> [(Integer,Integer,Integer)]
triples_bind n =
  [1 .. n] >>= \a ->
    [a .. n] >>= \b ->
      [b .. n] >>= \c ->
        (guard $ a*a + b*b == c*c) >>= \_ ->
          return (a,b,c)
triples_stacked :: Integer -> [(Integer,Integer,Integer)]
triples_stacked n =
  concatMap (\a ->
    concatMap (\b ->
      concatMap (\c ->
        concatMap (\_ ->
          [(a,b,c)])
          (guard $ a*a + b*b == c*c))
        [b .. n])
      [a .. n])
    [1 .. n]
triples_cm n = concatMap step2 [1 .. n]  -- step 1
  where step2 a = concatMap step3 [a .. n]
          where step3 b = concatMap step4 [b .. n]
                  where step4 c = concatMap step5 (guard $ a*a + b*b == c*c)
                          where step5 _ = [(a,b,c)]
go 0 = 0
go i =  case i of
            1 -> 2
            _ -> 3
        go (i-1)
go 0 = 0
go 1 = go (2 - 1)
go _ = go (3 - 1)
go 0 = 0
go x = let i = case x of 1 -> 2
                         _ -> 3
       in go (i - 1)
go 0 = 0
go x | x == 1    = go (2 - 1)
     | otherwise = go (3 - 1)
count ([],x) = x
count (_:b, x) =
    let y = x + 1
    in count (b, y)
count ([],x) = x
count (_:b, x) = count (b, x + 1)
count ([],x) = x
count (_:b, x) = count (b, y) where y = x + 1