[英]Calling Frege From Java Doesn't Match Number of Parameters
我有以下Frege代码(大多数情况下,只需注意getDatabase的类型签名)
module fregeHelper.FregeCode where
--Java's String.split method
pure native split :: String -> String -> JArray String
--Java's ArrayList<t>
data ArrayList t =native java.util.ArrayList where
native new :: () -> STMutable s (ArrayList t)
native add::Mutable s (ArrayList t)-> t -> ST s ()
getDatabase::String->(IO (STMutable s (ArrayList (String, String))))
getDatabase s = do
fileContents <- readFile s
let processedData = map ((\x->(elemAt x 0, elemAt x 1)) . (flip split ";")) . lines $ fileContents
return $ fold foldAdd (ArrayList.new ()) processedData
where
foldAdd::ST s (Mutable s (ArrayList t)) -> t -> ST s (Mutable s (ArrayList t))
foldAdd list elem = list >>= \x->(ArrayList.add x elem >> return x)
然后,我想从Java中定义以下函数(其中DATABASE是字符串常量):
private void readDatabase() {
myList = Delayed.<ArrayList<TTuple2>>forced(
fregeHelper.FregeCode.getDatabase(DATABASE));
}
但是,这给了我一个java.lang.ClassCastException: frege.prelude.PreludeBase$TST$1 cannot be cast to java.util.ArrayList
通过实验,我不得不将代码更改为
private void readDatabase() {
fighters = Delayed.<ArrayList<TTuple2>>forced(
fregeHelper.FregeCode.getDatabase(DATABASE)
.apply(null)
.apply(null)
);
}
我在后者中使用null只是为了表明我传入的内容无关紧要。我不知道为什么必须重复应用该函数三次(我不能立即强制求值)。 我有什么办法可以删除应用程序,也可以对为什么有必要进行合理化处理? (注意:使用.result()不能解决问题。)
这样做的原因是,在此实现中,ST动作表示为“功能对象”,在其中实现已实现功能的方法忽略了它的参数。
回顾一下ST的定义可能有助于理解:
abstract data ST s a = ST (s -> a) where ...
首先要注意的是,该data
实际上被写入newtype
在Haskell。 因此, ST
只是类型重命名,也就是说,ST动作实际上是一个函数。
但是, abstract
确保您无法浏览ST
数据构造函数,因此不能直接从Frege代码运行该函数。
这解释了为什么从Java将参数应用到返回ST
动作的函数后,需要将多余的参数应用于结果的原因,正如我们所看到的,该参数仅是另一个函数。
那么,为什么然后必须在代码中执行两次呢? 因为IO
是(从我的头开始):
type IO = ST RealWorld
STMutable
是
type STMutable s x = ST s (Mutable s x)
因此,问题出在getDatabase
函数上,该函数返回IO
动作,执行时返回ST动作,执行时返回可变的ArrayList。
这可能不是您想要的。 而且我猜想您在getDatabase
的最后一行getDatabase
挣扎,该行可能显示为:
list <- ArrayList.new ()
foldM (\xs\x -> ArrayList.add xs x >> return xs) list processedData
然后返回类型
IO (Mutable RealWorld ArraList)
要不就
IOMutable ArrayList
除此以外的另一点是:您不需要重新引入split
,它已经存在。 您可以编写以分号分隔的输入行分开的行:
[ (a,b) | line <- lines fileContent, [a,b] <- ´;´.splitted line ]
另请参见http://www.frege-lang.org/doc/frege/java/util/Regex.html#Regex.splitted和http://www.frege-lang.org/doc/frege/java/util/ Regex.html#Regex.split
Dierks的回答提出了一个有趣的观点,我们应该具有一个实用程序函数,用于从Java代码运行ST(或IO)操作。 实际上,有一个这样的函数,其名称为ST.performUnsafe
(在Frege中),在Haskell中称为unsafePerformIO
。
实际上,使用此功能将使Java代码对实现的更改更健壮,因此强烈建议代替此处使用的.apply(null)
代码。
我确信其他人可以提供更好的答案,但是在强制评估Delayed时必须传递的额外参数的原因是IO和STMutable类型。
我在这里遇到了相同的问题: https : //github.com/Frege/FregeFX/blob/f2f548071afd32a08e9b24f6fb6bbece74d4213b/fregefx/src/main/java/org/frege/FregeFX.java#L19-L19
可能值得考虑使用实用程序方法“ deeplyForced”(?),该方法可以使Java开发人员免受这些细节的影响。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.