Haskell:异构字符串列表的类型(无样板)and/or [String]?
Haskell: Type (without boilerplate) for a heterogeneous list of String and/or [String]?
我想要一个 String
和 [String]
的异构列表,例如:
strs = ["h", ["x", "y"], "i", ["m", "n", "p"]]
我知道我可以使用自定义数据类型来做到这一点:
data EitherOr t = StringS t | StringL [t]
eitherOrstrs :: [EitherOr String]
eitherOrstrs = [StringS "h", StringL ["x", "y"], StringS "i", StringL ["m", "n", "p"]]
但我很好奇这是否可以在没有任何样板的情况下实现,如上文 strs
所示。
到目前为止我已经尝试过:
{-# LANGUAGE ExistentialQuantification #-}
class Listable a where
toListForm :: [String]
instance Listable String where
toListForm s = [s]
instance Listable [String] where
toListForm = id
strs :: forall a. Listable a => [a]
strs = ["h", ["x", "y"], "i", ["m", "n", "p"]]
但是还没找到有效的方法:
The class method ‘toListForm’
mentions none of the type or kind variables of the class ‘Listable a’
When checking the class method: toListForm :: [String]
In the class declaration for ‘Listable’
有人知道这是否可行吗?
这将适用于具有一些扩展技巧的任意嵌套字符串列表:
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE OverloadedLists #-}
import GHC.Exts
import Data.String
data MyStringListThingy
= String String
| List [MyStringListThingy]
deriving (Eq, Show)
instance IsString MyStringListThingy where
fromString = String
instance IsList MyStringListThingy where
type Item MyStringListThingy = MyStringListThingy
fromList = List
fromListN _ = List
toList (String s) = [String s]
toList (List ss) = ss
strs :: MyStringListThingy
strs = ["h", ["x", "y"], "i", ["m", "n", "p", ["q", ["r", "s"]]]]
你至少需要 GHC 7.8,可能是 7.10(我还没有用 7.8 测试过)。
如果没有样板文件,这并不能完全摆脱,编译器将隐式函数调用放在每个文字的前面:
strs = fL [fS "h", fL [fS "x", fS "y"], fS "i", fL [fS "m", fS "n", fS "p", fL [fS "q", fL [fS "r", fS "s"]]]]
where
fL = fromList
fS = fromString
虽然没有 fL
和 fS
别名,但我只是这样做了,这样我就不必输入那么多了。它只是感觉没有样板文件,因为编译器为您放置了那些函数调用,但您仍然需要将这些值转换为 MyStringListThingy
.
的开销
你也可以使用这个技巧摆脱异构数字列表,因为数字文字也是多态的,这也是 OverloadedStrings
和 OverloadedLists
扩展对这些文字所做的.通过制作一个包装列表和字符串的类型,然后实例化您允许 Haskell 从这些文字转换为您的自定义类型的必要类型类。 TypeFamilies
扩展仅对 IsList
实例是必需的。如果你想在 GHCi 中使用它,你还必须在那里启用所有这些扩展,但它确实有效。
更通用的实现是
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE OverloadedLists #-}
import GHC.Exts
import Data.String
data NestedList a
= Item a
| List [NestedList a]
deriving (Eq, Show)
instance IsList (NestedList a) where
type Item (NestedList a) = NestedList a
fromList = List
fromListN _ = List
toList (List xs) = xs
toList item = [item]
instance IsString (NestedList String) where
fromString = Item
instance Num a => Num (NestedList a) where
fromInteger = Item . fromInteger
Num
实例并没有实现它需要的一切,只是足以炫耀它有效
> [1, [2, 3]] :: NestedList Int
List [Item 1, List [Item 2, Item 3]]
不过,我不建议在实际代码中使用它。
我想要一个 String
和 [String]
的异构列表,例如:
strs = ["h", ["x", "y"], "i", ["m", "n", "p"]]
我知道我可以使用自定义数据类型来做到这一点:
data EitherOr t = StringS t | StringL [t]
eitherOrstrs :: [EitherOr String]
eitherOrstrs = [StringS "h", StringL ["x", "y"], StringS "i", StringL ["m", "n", "p"]]
但我很好奇这是否可以在没有任何样板的情况下实现,如上文 strs
所示。
到目前为止我已经尝试过:
{-# LANGUAGE ExistentialQuantification #-}
class Listable a where
toListForm :: [String]
instance Listable String where
toListForm s = [s]
instance Listable [String] where
toListForm = id
strs :: forall a. Listable a => [a]
strs = ["h", ["x", "y"], "i", ["m", "n", "p"]]
但是还没找到有效的方法:
The class method ‘toListForm’
mentions none of the type or kind variables of the class ‘Listable a’
When checking the class method: toListForm :: [String]
In the class declaration for ‘Listable’
有人知道这是否可行吗?
这将适用于具有一些扩展技巧的任意嵌套字符串列表:
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE OverloadedLists #-}
import GHC.Exts
import Data.String
data MyStringListThingy
= String String
| List [MyStringListThingy]
deriving (Eq, Show)
instance IsString MyStringListThingy where
fromString = String
instance IsList MyStringListThingy where
type Item MyStringListThingy = MyStringListThingy
fromList = List
fromListN _ = List
toList (String s) = [String s]
toList (List ss) = ss
strs :: MyStringListThingy
strs = ["h", ["x", "y"], "i", ["m", "n", "p", ["q", ["r", "s"]]]]
你至少需要 GHC 7.8,可能是 7.10(我还没有用 7.8 测试过)。
如果没有样板文件,这并不能完全摆脱,编译器将隐式函数调用放在每个文字的前面:
strs = fL [fS "h", fL [fS "x", fS "y"], fS "i", fL [fS "m", fS "n", fS "p", fL [fS "q", fL [fS "r", fS "s"]]]]
where
fL = fromList
fS = fromString
虽然没有 fL
和 fS
别名,但我只是这样做了,这样我就不必输入那么多了。它只是感觉没有样板文件,因为编译器为您放置了那些函数调用,但您仍然需要将这些值转换为 MyStringListThingy
.
你也可以使用这个技巧摆脱异构数字列表,因为数字文字也是多态的,这也是 OverloadedStrings
和 OverloadedLists
扩展对这些文字所做的.通过制作一个包装列表和字符串的类型,然后实例化您允许 Haskell 从这些文字转换为您的自定义类型的必要类型类。 TypeFamilies
扩展仅对 IsList
实例是必需的。如果你想在 GHCi 中使用它,你还必须在那里启用所有这些扩展,但它确实有效。
更通用的实现是
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE OverloadedLists #-}
import GHC.Exts
import Data.String
data NestedList a
= Item a
| List [NestedList a]
deriving (Eq, Show)
instance IsList (NestedList a) where
type Item (NestedList a) = NestedList a
fromList = List
fromListN _ = List
toList (List xs) = xs
toList item = [item]
instance IsString (NestedList String) where
fromString = Item
instance Num a => Num (NestedList a) where
fromInteger = Item . fromInteger
Num
实例并没有实现它需要的一切,只是足以炫耀它有效
> [1, [2, 3]] :: NestedList Int
List [Item 1, List [Item 2, Item 3]]
不过,我不建议在实际代码中使用它。