在纯脚本中使用随机类型检查错误

Type checking error useing random in purescript

使用以下代码 insertRnd 可以正常工作,但我无法进行加扰或使用 insertRnd 进行编译的任何其他操作:

scramble :: ∀ eff. String -> Eff (random :: RANDOM | eff) String
scramble s = foldl insertRnd (take 1 s) (drop 1 s)

insertRnd :: ∀ eff. String -> String -> Eff (random :: RANDOM | eff) String
insertRnd st ch = do
  n <- randomInt 0 $ length st
  pure $ insertAt n ch st

我收到以下错误消息

Could not match type

Eff
  ( random :: RANDOM
  | t2
  )
  String

with type

String

while checking that type forall eff.
                       String
                       -> String
                          -> Eff
                               ( random :: RANDOM
                               | eff
                               )
                               String
is at least as general as type t0 -> t1 -> t0
while checking that expression insertRnd
has type t0 -> t1 -> t0
in value declaration scramble

where t0 is an unknown type
  t1 is an unknown type
  t2 is an unknown type

我做错了什么?

首先,你的insertRnd本身并没有为我编译,因为没有函数insertAt :: Int -> String -> String -> String(甚至Int -> Char -> String -> String, see below). There is such function for arrays and lists and some other stuff,但不是字符串。我在这里假设你自己编写了这样的函数并且它存在于你的代码中。

Second,即使它编译了,它也有错误的 fold 签名:你试图折叠 String,它包含 Chars,这意味着折叠函数的第二个参数必须是 Char。所以在这里我假设你的 insertRnd 实际上有以下签名:

insertRnd :: ∀ eff. String -> Char -> Eff (random :: RANDOM | eff) String

Third,实际上 foldl 不能超过 String,因为 String 没有 [=] 的实例25=]。要折叠字符串的字符,您需要先将字符串转换为 Char 的数组(或其他一些容器)。幸运的是,有一个有用的函数 - toCharArray.

第四,你关于无法编译"anything else that uses insertRnd"的说法可能过于宽泛。这是一个使用 insertRnd:

的 "anything else" 的完美可编译示例
main = launchAff do
    x <- liftEff $ insertRnd "abcd" 'x'
    log x

最后,你的foldl没有编译的原因是foldl需要一个纯函数a -> b -> a作为第一个参数, 但你给了它一个有效的功能 a -> b -> Eff _ a。难怪类型不匹配!

foldl的有效类比是foldM。这个函数做了类似的事情,除了它在 monad 中链接调用而不是进行纯函数组合。例如:

foldM insertRnd "a" ['b', 'c', 'd']

将上述所有内容应用到您的代码中,这是最终版本(假设存在 insertAt :: Int -> Char -> String -> String):

scramble :: ∀ eff. String -> Eff (random :: RANDOM | eff) String
scramble s = foldM insertRnd (take 1 s) (toCharArray $ drop 1 s)

insertRnd :: ∀ eff. String -> Char -> Eff (random :: RANDOM | eff) String
insertRnd st ch = do
  n <- randomInt 0 $ length st
  pure $ insertAt n ch st