我正在尝试用Scala编写一个名为'Rock'的Haskell库中的一些核心数据库。
正如上面链接项目的README
中所提到的,库的想法大致基于here的论文。
以下是Rock库(Haskell)中使用的核心类型:
// in src/Core.hs (
type Rules f = GenRules f f
-- | A function which, given an @f@ query, returns a 'Task' allowed to make @g@
-- queries to compute its result.
type GenRules f g = forall a. f a -> Task g a
-- | An @IO@ action that is allowed to make @f@ queries using the 'fetch'
-- method from its 'MonadFetch' instance.
newtype Task f a = Task { unTask :: ReaderT (Fetch f) IO a }
deriving
(Functor, Applicative, Monad, MonadIO, MonadBase IO, MonadFix)
newtype Fetch f = Fetch (forall a. f a -> IO a)
字符串
有些看起来比构建系统中的那些更简单(例如:Task
类型,它是IO上的瘦抽象)
我很好奇在Scala中以类似的方式建模是否可能/可行。
在对Scala中的“forall”类型做了一些阅读之后(并参考了旧的线程,如this one),我从以下内容开始:
object Core {
type Rules[F[_]] = GenRules[F[_], F[_]] //<- scala err: "Type argument F[?] does not have the same kind as its bound [_$2]"
type GenRules[F[_], G[_]] = [A] => (F[_] => Task[G[_], A])
type Task[F[_], A] = ReaderT[Fetch[F[_]], A]
type Fetch[F[_]] = /*forall*/ [A] => (F[A] => IO[A])
}
型
我很难理解为什么我不能用F[_]
专门化GenRules
类型.
还有:接下来,无论这些类型在Scala 3(或2)中采用何种形式,我们的目标都是复制Rock repo主页中演示的电子表格示例。
// Spreadsheet.hs (https://github.com/ollef/rock/blob/master/examples/Spreadsheet.hs)
data Query a where
A :: Query Integer
B :: Query Integer
C :: Query Integer
D :: Query Integer
rules :: Rock.Rules Query
rules key = do
liftIO $ putStrLn $ "Fetching " <> show key
case key of
... -- rest elided
型
Scala版本:
// GADT for the sample/example `Query` type
enum Query[A]:
case A extends Query[Int]
case B extends Query[Int]
case C extends Query[Int]
case D extends Query[Int]
def rules() : Core.Rules[Query] =
// ????
型
在原始的haskell代码中,rules
函数中提到的key
是Query a
类型。有一点:rules
函数不接受输入。。那么Core.Rules[Query]
是某种部分应用的类型吗?
任何对这些问题的深入了解都是有帮助的--我并不一定关心达到“惯用”的Scala代码
1条答案
按热度按时间57hvy0tb1#
类型参数定义中的
F[_]
表示“类型构造函数 * -> *"。类型应用程序中的F[_]
表示“存在类型”。Scala 3倾向于为这些类型使用两种不同的语法,但Scala 2中的旧语法仍然会被解析。在F
应用程序中删除[_]
,因为它的友好性与预期不符。GenRules应该应用从
[A] =>
获得的A
。字符串
一旦我们做了去锯齿练习,我们就知道我们需要定义什么样的值:
型
编辑:
实际上,如果我们进一步去别名,一个实现变得有点明显:
型
这里你有一个类型参数方法,它接受值(键),然后接受另一个类型参数方法来应用该值。由于
Rules
的类型是多态函数,它接受参数的事实在它的定义中是隐藏的,但是当你示例化它时,你必须以某种方式传递这些参数。然后你会定义。在Haskell中,所有函数都是curry的,所以如果你只定义了第一个参数,那么就假定你将返回一些会消耗剩余参数的东西。