haskell类型、新类型或仅用于大写字符的数据

haskell类型、新类型或仅用于大写字符的数据,haskell,Haskell,如果我想生成一个字符串,但只包含一个大写字符。我知道字符串是[Char]。我尝试过类似于typea=['a'..'Z']的方法,但没有任何帮助?您想要的是依赖类型,而Haskell没有。依赖类型是那些依赖于值的类型,因此使用依赖类型可以在类型级别将长度为5的向量编码为 only5 :: Vector 5 a -> Vector 10 a only5 vec = concatenate vec vec 同样,Haskell没有依赖类型,但Agda、Coq和Idris等语言确实支持它们。相反

如果我想生成一个字符串,但只包含一个大写字符。我知道字符串是[Char]。我尝试过类似于
typea=['a'..'Z']
的方法,但没有任何帮助?

您想要的是依赖类型,而Haskell没有。依赖类型是那些依赖于值的类型,因此使用依赖类型可以在类型级别将长度为5的向量编码为

only5 :: Vector 5 a -> Vector 10 a
only5 vec = concatenate vec vec
同样,Haskell没有依赖类型,但Agda、Coq和Idris等语言确实支持它们。相反,您可以使用“智能构造函数”

这里不导出构造函数
Upper
,只导出类型,然后此模块的用户必须使用
mkUpper
函数安全地拒绝非大写字符串


用于澄清,并显示依赖性类型是多么可怕,请考虑上面的神秘<代码>级联< /代码>函数。如果我用依赖类型定义它,它实际上看起来像

concatenate :: Vector n a -> Vector m a -> Vector (n + m) a
concatenate v1 v2 = undefined

等等,算术在类型签名中做什么?它实际上是对该类型所依赖的值执行类型系统级计算。这删除了Haskell中大量潜在的样板文件,并保证在编译时,例如数组不能有负长度。

bheklillr是正确的,但可能出于您的目的,以下内容可以:

import Data.Char(toUpper)

newtype UpperChar = UpperChar Char
deriving (Show)

upperchar :: Char -> UpperChar
upperchar = UpperChar. toUpper

您也可以将UpperChar作为Char的别名(使用type而不是newtype),这将允许您形成Char和UpperChar的列表。但是,别名的问题在于,您可以将字符输入到一个需要大写字符的函数中。

一种类似的方法可以很好地处理您选择的拉丁语脚本,但没有完全通用的解决方案那么好,就是使用自定义类型来表示大写字母。像这样的事情应该可以做到:

data UpperChar = A|B|C|D| (fill in the rest) | Y | Z deriving (Enum, Eq, Ord, Show)

newtype UpperString = UpperString [UpperChar]

instance Show UpperString
    show (UpperString s) = map show s

此类型的成员不是Haskell
String
s,但您可以根据需要在它们之间进行转换。

可以使用智能构造函数(参见Bheklillr的答案)、从外部工具(Coq、Isabelle、Inch等)生成Haskell或使用精确表示来满足依赖类型的大多数需求。您可能想要第一个解决方案

为了准确地表示大写字母,您可以编写一个数据类型,其中包括每个字母的构造函数以及与字符串的转换:

data Capital = CA | CB | CC | CD | CE | CF | CG | CH | CI | CJ | CK | CL | CM | CN | CO | CP | CQ | CR | CS | CT | CU | CV | CW | CX | CY | CZ deriving (Eq, Ord, Enum)


toString :: [Capital] -> String
toString = map (toEnum . (+ (fromEnum 'A')) . fromEnum)
您甚至可以更进一步,通过使用
重载字符串
扩展名,允许从字符串文本,
“引号中的任何内容”
,转换为类型
[大写字母]
。只需在文件顶部添加
{-#语言重载字符串,FlexibleInstances{-}
,确保
导入数据.String
并编写实例:

type Capitals = [Capital]

instance IsString Capitals where
    fromString = map (toEnum . (subtract (fromEnum 'A')) . fromEnum) . filter (\x -> 'A' <= x && x <= 'Z')

这在实践中就像有依赖类型:)伟大的答案(像往常一样)!
type Capitals = [Capital]

instance IsString Capitals where
    fromString = map (toEnum . (subtract (fromEnum 'A')) . fromEnum) . filter (\x -> 'A' <= x && x <= 'Z')
*Main> toString ("jfoeaFJOEW" :: Capitals)
"FJOEW"
*Main>