gpt4 book ai didi

string - Haskell中如何根据字符串解析的结果返回多态类型?

转载 作者:行者123 更新时间:2023-12-04 04:54:59 25 4
gpt4 key购买 nike

TL;DR:
如何编写返回类型为多态的函数?我正在做一个练习,任务是编写一个能够分析 String 的函数。并根据其内容生成 Vector [Int] , Vector [Char]Vector [String] .

加长版:
以下是预期功能如何表现的一些示例:

  • 字符串 "1 2\n3 4"将生成 Vector [Int]由两个列表组成:[1,2][3,4] .
  • 字符串 "'t' 'i' 'c'\n't' 'a' 'c'\n't' 'o' 'e'"将生成 Vector [Char] (即,由列表 "tic""tac""toe" 组成)。
  • 字符串 "\"hello\" \"world\"\n\"monad\" \"party\""将生成 Vector [String] (即 ["hello","world"]["monad","party"] )。

  • 错误检查/异常处理不是这个特定练习的关注点。在这个阶段,所有的测试都是纯粹完成的,也就是说,这不在 IO 的范围内。单子(monad)。

    到目前为止我所拥有的:

    我有一个能够对字符串进行分类的函数(和新的数据类型)。我也有函数(每个 IntCharString 一个)可以将字符串转换为必要的向量。

    我的问题:如何将这三个转换函数组合成一个函数?

    我试过的:
  • (如果我填充三个转换,它显然不会进行类型检查
    将函数合并为单个函数(即,使用 case..of 结构
    VectorType 上进行模式匹配的字符串。
  • 我尝试制作 Vectorable类并为每种类型定义一个单独的实例;我很快意识到这种方法只有在函数的参数因类型而异时才有效。在我们的例子中,参数的类型没有变化(即,它总是一个 String )。

  • 我的代码:

    几点评论
  • 解析:mySplitter对象和 mySplit函数处理解析。诚然,它是基于 Splitter 的粗略解析器。类型和 split函数来自 Data.List.Split.Internals .
  • 分类:classify函数能够确定最终 VectorType基于字符串。
  • 转换:toVectorNumber , toVectorChartoVectorString函数能够将字符串转换为类型 Vector [Int] , Vector [Char]Vector [String] , 分别。
  • 作为旁注,我正在尝试 CorePrelude根据导师的推荐。这就是为什么你会看到我使用普通 Prelude 函数的通用版本。

  • 代码:
    import qualified Prelude
    import CorePrelude

    import Data.Foldable (concat, elem, any)
    import Control.Monad (mfilter)
    import Text.Read (read)
    import Data.Char (isAlpha, isSpace)

    import Data.List.Split (split)
    import Data.List.Split.Internals (Splitter(..), DelimPolicy(..), CondensePolicy(..), EndPolicy(..), Delimiter(..))

    import Data.Vector ()
    import qualified Data.Vector as V

    data VectorType = Number | Character | TextString deriving (Show)

    mySplitter :: [Char] -> Splitter Char
    mySplitter elts = Splitter { delimiter = Delimiter [(`elem` elts)]
    , delimPolicy = Drop
    , condensePolicy = Condense
    , initBlankPolicy = DropBlank
    , finalBlankPolicy = DropBlank }

    mySplit :: [Char]-> [Char]-> [[Char]]
    mySplit delims = split (mySplitter delims)

    classify :: String -> VectorType
    classify xs
    | '\"' `elem` cs = TextString
    | hasAlpha cs = Character
    | otherwise = Number
    where
    cs = concat $ split (mySplitter "\n") xs
    hasAlpha = any isAlpha . mfilter (/=' ')

    toRows :: [Char] -> [[Char]]
    toRows = mySplit "\n"

    toVectorChar :: [Char] -> Vector [Char]
    toVectorChar = let toChar = concat . mySplit " \'"
    in V.fromList . fmap (toChar) . toRows

    toVectorNumber :: [Char] -> Vector [Int]
    toVectorNumber = let toNumber = fmap (\x -> read x :: Int) . mySplit " "
    in V.fromList . fmap toNumber . toRows

    toVectorString :: [Char] -> Vector [[Char]]
    toVectorString = let toString = mfilter (/= " ") . mySplit "\""
    in V.fromList . fmap toString . toRows

    最佳答案

    你不能。

    Haskell 不支持协变多态性,如果支持的话也不会有用。

    这基本上就是所有要回答的问题。现在至于为什么会这样。

    像 OO 语言那样“返回多态值”并不好,因为返回任何值的唯一原因就是在其他函数中使用它。现在,在 OO 语言中,您没有函数,而是对象附带的方法,因此“返回不同类型”非常容易:每种方法都内置了合适的方法,并且每个实例都可以不同。 (这是否是一个好主意是另一个问题。)

    但是在 Haskell 中,函数来自其他地方。他们不知道特定实例的实现更改,因此可以安全地定义此类函数的唯一方法是了解每个可能的实现。但是,如果您的返回类型真的是多态的,那是不可能的,因为多态是一个“开放”的概念(它允许以后随时添加新的实现变体)。

    相反,Haskell 有一个非常方便且完全安全的机制来描述一组封闭的“实例”——您实际上已经自己使用过它! ADT。

    data PolyVector = NumbersVector (Vector [Int])
    | CharsVector (Vector [Char])
    | StringsVector (Vector [String])

    这就是你想要的返回类型。该函数本身不会是多态的,它只会返回一个更通用的类型。

    如果你坚持它应该是多态的

    现在......实际上,Haskell 确实有办法处理“多态返回”。就像在 OO 中一样,当您声明返回指定类的子类时。好吧,在 Haskell 中你根本不能“返回一个类”,你只能返回类型。但是这些可以用来表达“...的任何实例”。它被称为存在量化。
    {-# LANGUAGE GADTs #-}

    data PolyVector' where
    PolyVector :: YourVElemClass e => Vector [e] -> PolyVector'

    class YourVElemClass where
    ...?
    instance YourVElemClass Int
    instance YourVElemClass Char
    instance YourVElemClass String

    我不知道这对你是否有吸引力。事实是,它要复杂得多,而且更难使用。您不能直接使用任何可能的结果,而只能通过 YourVElemClass 的方法使用元素. GADT 在某些应用程序中可能非常有用,但这些通常涉及具有非常深刻的数学动机的类。 YourVElemClass似乎没有这样的动机,所以与存在量化相比,使用简单的 ADT 替代方案会好得多。

    a famous rant against existentials by Luke Palmer (注意他使用了另一种语法,存在特定的,我认为它已经过时了,因为 GADT 严格来说更通用)。

    关于string - Haskell中如何根据字符串解析的结果返回多态类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26940670/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com