模块Type.hs
定义了谐音newtype
,只导出其类型构造函数,不导出值构造函数,避免暴露细节;它还提供了一个构造函数makeType
来平衡缺少值ctor。为什么我需要将 a 包装成String
一个新类型?因为我希望它不仅仅是一个String
; 在我的具体情况下,Type
实际上被称为Line
,并且对应于makeType
强制它只包含一个\n
,作为最后一个字符。Anewtype
对我来说似乎是最明显的选择。如果不是这样,请原谅我:我正在学习。
module Type (Type, makeType) where
newtype Type = Type String
makeType :: String -> Type
makeType = Type
为了以Type
我喜欢的方式显示类型的值(例如,给定我的实际用例Line
,我可能想\n
用一个漂亮的 unicode 字符或序列<NL>
或其他方式表示),我创建了另一个模块TypeShow.hs
,我稍后(在尝试做我所描述的事情时)我通过添加一些编译指示进行了编辑。为什么是另一个模块?因为我猜某些东西在内部的运作方式和我在屏幕上展示它的方式是两个独立的方面。我错了吗?
{-# LANGUAGE FlexibleInstances #-}
module TypeShow () where
import Type
instance Show Type where
show = const "Type"
-- the following instance came later, see below why
instance {-# OVERLAPS #-} Show (Maybe Type) where
show (Just t) = show t
show _ = ""
除了这对模块(描述 的核心Type
,以及它应该如何显示)之外,我还创建了其他类似的对Type1
/ Type1Show
,Type2
/ Type2Show
,它们都包裹 aString
来表示和显示其他类似String
实体。
Type
由于其他原因,我还需要另一种包装可选值的类型,它可以是Type1
, 或任何其他类型,所以我编写了这个模块
module Wrapper (Wrapper, makeWrapper, getInside) where
newtype Wrapper a = Wrapper { getInside :: Maybe a }
makeWrapper :: a -> Wrapper a
makeWrapper = Wrapper . Just
(实际上Wrapper
实际上包装了多个Type
值,但我会避免提供更多必要的细节;如果以下内容很愚蠢,因为我只在 中包装了一个Type
值Wrapper
,那么请考虑它实际上包装了多个值。)同样,在这里我试图隐藏细节,Wrapper
同时提供makeWrapper
制作一个,并getInside
对其内部进行“受控”访问。
我也想在屏幕上显示这个,所以我创建了一个相应的WrapperShow.hs
模块,所以它Wrapper
的show
方法依赖于内容的show
方法。
module WrapperShow () where
import Wrapper
instance Show a => Show (Wrapper a) where
show = show . getInside
然而,此时,当类型a
为 a时Maybe Type
,我想显示Wrapper
打印空字符串的内容,而不是Nothing
,或 ; 的内容Just
。因此,我写了instance Show (Maybe Type)
我在上面评论过的内容。
鉴于此,Type "hello"
andJust $ Type "hello"
都正确显示为Type
,但Wrapper $ Just $ Type "hello"
显示为Just Type
,就像它使用Maybe
的原始实例一样,无论对于( )Show
中的这种特定类型,我已经自定义了实例。Maybe
Type
Show