背景:我正在开发一个声明式编译器。在本课程中,我将编写一个类来构建一个中间数据结构。构建数据结构后,可以从数据结构重新渲染输出。为了简化 stackoverflow,我创建了以下代码:
module Main where
import qualified Data.Word as W
import qualified Octetable as Oct
main :: IO ()
main =
do
print (buildNRender "123")
data MyData = MyData Integer
data Construction model = Contains model | Error String
deriving Show
class Builder g where
build :: String -> (Construction g)
render :: (Construction g) -> [W.Word8]
buildNRender :: String -> [W.Word8]
buildNRender = render . build
instance Builder MyData where
build s = Contains (MyData (read s :: Integer))
render (Contains (MyData n)) = Oct.toOctets n
render (Error _) = []
Run Code Online (Sandbox Code Playgroud)
明显的问题是,'buildNRender' 不能成为 Builder 的一部分,因为根本没有使用类型参数 g。
现在,对我来说很明显类型类不能像这样工作,其中两个或多个函数的组合中的中间值具有类型参数。
以下代码使中间类型显式,并且有效 - 但没有 buildNRender。
...
main :: IO ()
main =
do
print (render ((build "123") :: (Construction MyData))
...
Run Code Online (Sandbox Code Playgroud)
但是,是否有一种优雅的方法来定义类的这种 DEFAULT 方法(如“buildNRender”),并在调用者的上下文中指定中间类型,如以下代码所示?
...
main :: IO ()
main =
do
print ((buildNRender "123") :: ?(Construction MyData)?)
...
Run Code Online (Sandbox Code Playgroud)
明显的问题是,
buildNRender不能是 的一部分Builder,因为g根本不使用类型参数。
嗯,这曾经是一个问题(具体来说,这g将是模棱两可的),但不再是因为 GHC 现在具有允许使用此类参数的扩展。
{-# LANGUAGE AllowAmbiguousTypes, TypeApplications, ScopedTypeVariables, UnicodeSyntax #-}
module Main where
import qualified Data.Word as W
import qualified Octetable as Oct
main :: IO ()
main =
do
print (buildNRender @MyData "123")
data MyData = MyData Integer
data Construction model = Contains model | Error String
deriving Show
class Builder g where
build :: String -> (Construction g)
render :: (Construction g) -> [W.Word8]
buildNRender :: ? g . Builder g => String -> [W.Word8]
-- ? (forall) g . introduces the type variable g into scope
-- needs extension AllowAmbiguousTypes
buildNRender = render . build @g -- @g is a Type Application
instance Builder MyData where
build s = Contains (MyData (read s :: Integer))
render (Contains (MyData n)) = Oct.toOctets n
render (Error _) = []Run Code Online (Sandbox Code Playgroud)
或者,没有UnicodeSyntax:
{-# LANGUAGE AllowAmbiguousTypes, TypeApplications, ScopedTypeVariables #-}
...
buildNRender :: forall g . Builder g => String -> [W.Word8]
Run Code Online (Sandbox Code Playgroud)