在纯脚本中使用随机类型检查错误
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
,它包含 Char
s,这意味着折叠函数的第二个参数必须是 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
使用以下代码 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
,它包含 Char
s,这意味着折叠函数的第二个参数必须是 Char
。所以在这里我假设你的 insertRnd
实际上有以下签名:
insertRnd :: ∀ eff. String -> Char -> Eff (random :: RANDOM | eff) String
Third,实际上 foldl
不能超过 String
,因为 String
没有 [=] 的实例25=]。要折叠字符串的字符,您需要先将字符串转换为 Char
的数组(或其他一些容器)。幸运的是,有一个有用的函数 - toCharArray
.
第四,你关于无法编译"anything else that uses insertRnd
"的说法可能过于宽泛。这是一个使用 insertRnd
:
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