我有以下Haskell代码:
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("MainMenu.fxml"));
// or just FXMLLoader loader = new FXMLLoader(getClass().getResource("MainMenu.fxml"));
Parent root = loader.load();
我之前建议让type family Element t
class ToList t where
toList :: t -> [Element t]
成为相关类型系列:Foldable IntSet
我试图实现这种方法。但它对我的情况不起作用。这是完整的代码:
Element
当我使用{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeFamilies #-}
import Prelude hiding (toList)
import qualified Data.Foldable as Foldable (toList)
import Data.Text (Text, unpack)
class ToList t where
type Element t :: *
toList :: t -> [Element t]
-- | This instance makes 'ToList' compatible and overlappable by 'Foldable'.
instance {-# OVERLAPPABLE #-} Foldable f => ToList (f a) where
type Element (f a) = a
toList = Foldable.toList
instance ToList Text where
type Element Text = Char
toList = unpack
newtype WrappedList l = WrappedList l
instance ToList l => ToList (WrappedList l) where
type Element (WrappedList l) = Element l
toList (WrappedList l) = toList l
编译此代码时,我看到以下错误:
GHC-8.2.2
我如何解决此错误?我不知道如何使这个与相关类型系列相容...
答案 0 :(得分:5)
基本问题是您无法使用类型重叠来制作重叠的类型系列。它根本没有意义 - 类型族从输入类型计算类型,结果类型可能不依赖于编译器如何选择类型类实例(否则它不会是一个函数 - 因为函数的输出可能只取决于输入)。这个问题很常见,但是你如何解决它完全取决于你的具体用例。
最简单的解决方案是使用DefaultSignatures
提供默认实现。请注意,关联的类型系列也可以具有默认值:
type family ElementDefault (t :: *) :: * where
ElementDefault (f a) = a
class ToList t where
type Element t :: *
type Element t = ElementDefault t
toList :: t -> [Element t]
default toList :: (Foldable f, t ~ f a, Element t ~ a) => t -> [Element t]
toList = Foldable.toList
这允许您为所有Foldable
类型编写实例,而不提供实现:
instance ToList [a]
instance ToList (Maybe a)
-- etc...
如果要避免编写此类实例(甚至是实例头),则需要将关联类型移动到类实例头中。由于只有可能重叠的类,而不是开放式类,所以这样做可以使“元素”成为可能。类型也重叠。
class ToList t e | t -> e where
toList :: t -> [e]
instance {-# OVERLAPPABLE #-} (a ~ a', Foldable f) => ToList (f a) a' where
toList = Foldable.toList
instance ToList Text Char where
toList = unpack
instance ToList l a => ToList (WrappedList l) a where
toList (WrappedList l) = toList l
提供多个默认定义的最简单方法是在类之外提供它们。如果你有15个类功能,这确实很乏味。在这种情况下,我会用记录实现该类:
data ToList' t e = ToList'
{ toList' :: t -> [e] {- 14 more fields... -} }
class ToList t where
type Element t
toList_impl :: ToList' t (Element t)
-- For consumers of ToList
toList :: ToList t => t -> [Element t]
toList = toList' toList_impl
instance ToList Text where
type Element Text = Char
toList_impl = ToList' unpack
toList_Foldable_default :: Foldable f => ToList' (f a) a
toList_Foldable_default = ToList' Foldable.toList
toList_Wrapped_list :: ToList l => ToList' l (Element l)
toList_Wrapped_list = ToList' toList
通过这种方法,您可以完全省去类型类;它唯一剩下的用途是获得实例唯一性。