【问题标题】:Why can't I call a function quicksort (randomList 10)?为什么我不能调用函数快速排序(randomList 10)?
【发布时间】:2019-04-20 16:55:54
【问题描述】:

我有以下代码:

import Data.Array
import Control.Monad
import Data.Functor 
import System.Random (randomRIO)

randomList 0 = return []
randomList n = do
  r  <- randomRIO (1,6)
  rs <- randomList (n-1)
  return (r:rs) 

quicksort [] = []  
quicksort (x:xs) =   
    let smallerSorted = quicksort [a | a <- xs, a <= x]  
        biggerSorted = quicksort [a | a <- xs, a > x]  
    in  smallerSorted ++ [x] ++ biggerSorted  
  1. randomList - 创建一个给定长度的列表并用随机值填充它;
  2. 快速排序 - 快速排序列表。

我需要对创建的数组进行排序: quicksort (randomList 10),但是出现错误:

"Couldn't match expected type‘ [a] ’with actual type IO [Int]’"

【问题讨论】:

  • 你应该fmap quicksort (randomList 10)
  • 您应该在程序中包含所有顶级名称的类型签名。如果您不认识他们,请加载文件并询问 GHCi:Main&gt; :t randomList。然后将其复制粘贴到文件中(或根据您的需要先对其进行专门化)。将类型签名放在它描述的名称上方。
  • @WillemVanOnsem,是的,很好,就是这样。

标签: haskell type-mismatch io-monad do-notation


【解决方案1】:

您应该在程序中包含所有顶级名称的类型签名。如果您不认识他们,请加载文件并询问 GHCi:Main&gt; :t randomList。然后将其复制粘贴到文件中(或根据您的需要先对其进行专门化)。将类型签名放在它描述的名称上方。

GHCi 说

randomList ::
  (System.Random.Random t, Num t, Num a, Eq a) => a -> IO [t]

但你的意思很可能是

randomList :: (System.Random.Random t, Num t) => Int -> IO [t]
randomList 0 = return []
randomList n = do
  r  <- randomRIO (1,6)    -- randomRIO (1,6) :: IO t  , r :: t
  rs <- randomList (n-1)   --             rs :: [t]
  return (r:rs)            --    r :: t , rs :: [t] 

一般来说,

randomRIO (1,6) :: (System.Random.Random a, Num a) => IO a

您投了一个 6 面骰子n 次,并将结果收集到一个列表中。顺便说一句,同样的事情是由

sequence $ replicate n (randomRIO (1,6))
===
replicateM n (randomRIO (1,6))

> :t \n -> replicateM n (randomRIO (1,6))
           :: (System.Random.Random a, Num a) => Int -> IO [a]

那么,GHCi 也告诉我们

 quicksort :: Ord t => [t] -> [t]

但是randomList nIO [t],而不是[t]。要获得位于IO [t] 内部的[t] 值,您需要在内部

sortRandom :: (Ord t, Monad m) => m [t] -> m [t]
sortRandom randomlist = do
    xs <- randomlist        -- randomlist :: IO [t] , xs :: [t]
    let ys = quicksort xs
    return ys

以上可以简写为

sortRandom :: (Ord t, Monad m) => m [t] -> m [t]
sortRandom = liftM quicksort     -- for monads

sortRandom :: (Ord t, Functor f) => f [t] -> f [t]
sortRandom = fmap quicksort      -- for functors

随你喜欢。两者都与 IO 一起工作,这是一个单子,任何单子也是一个函子。所以最后你可以定义

foo :: Int -> IO [Int]
foo n = liftM quicksort $ replicateM n (randomRIO (1,6))

【讨论】:

  • 编译时,我在这一行得到一个错误:“randomList :: (System.Random.Random t, Num t) => Int -> IO [t]” 不在范围内:类型构造函数或类'System.Random.Random'
  • import System作为一个整体,没有(randomRIO)
  • 之后可以执行以下操作吗? sort n = dolist &lt;- randomList nlet res = sortRandom listreturn res
  • 没有。按照类型! (这是 Haskell 的一般口号)。一个一个,慢慢地,写下类型:randomList n :: IO [Int];因此,list :: [Int]sortRandom :: (Monad m) =&gt; m [Int] -&gt; m [Int],或专门用于IOsortRandom :: IO [Int] -&gt; IO [Int]。这意味着它是一个需要IO [Int] 的函数,而不仅仅是[Int]。所以list :: [Int] 不能成为它的论据。但是我们有quicksort 可以接受[Int] 参数,所以对于let res = quicksort listres :: [Int]。所以return res :: IO [Int]。我很快就会搜索到do 解释的链接...
  • @Vasiliy,如果您在IO 工作,并且具有随机性,您应该真正使用真正的快速排序而不是那个假的!唯一棘手的事情是您必须从列表切换到数组。当然,如果你不专注于快速排序,你几乎肯定应该使用不同的算法来代替:自底向上的归并排序在 Haskell 中非常好用,堆排序也可以。
猜你喜欢
  • 2014-08-02
  • 1970-01-01
  • 2011-06-02
  • 1970-01-01
  • 2018-03-28
  • 2014-09-14
  • 2021-06-19
  • 2021-11-03
  • 2015-03-19
相关资源
最近更新 更多