Haskell:为String和/或[String]的异构列表键入(没有样板)?

spa*_*sue 2 haskell types list existential-type heterogeneous

我想有一个异构的名单String[String],因此:

strs = ["h", ["x", "y"], "i", ["m", "n", "p"]]
Run Code Online (Sandbox Code Playgroud)

我知道我可以使用自定义数据类型执行此操作:

data EitherOr t = StringS t | StringL [t]

eitherOrstrs :: [EitherOr String]
eitherOrstrs = [StringS "h", StringL ["x", "y"], StringS "i", StringL ["m", "n", "p"]]
Run Code Online (Sandbox Code Playgroud)

但我很好奇这是否可能没有任何样板,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"]]
Run Code Online (Sandbox Code Playgroud)

但还没有找到一种工作方法:

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’
Run Code Online (Sandbox Code Playgroud)

有谁知道这是否可能?

bhe*_*ilr 7

这适用于具有一些扩展技巧的任意嵌套字符串列表:

{-# 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"]]]]
Run Code Online (Sandbox Code Playgroud)

你需要至少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
Run Code Online (Sandbox Code Playgroud)

虽然没有fLfS别名,我只是这样做,所以我不必打那么多.它只是感觉没有样板,因为编译器会为你放置那些函数调用,但是你仍然会有将这些值转换成的开销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
Run Code Online (Sandbox Code Playgroud)

Num实例没有实现它所需要的一切,只是足以证明这是有效的

> [1, [2, 3]] :: NestedList Int
List [Item 1, List [Item 2, Item 3]]
Run Code Online (Sandbox Code Playgroud)

不过,我不建议在实际代码中使用它.

  • 我同时感到印象深刻和反感. (6认同)