繁体   English   中英

从Java调用Frege与参数数量不匹配

[英]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.splittedhttp://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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM