【问题标题】:Returning different types in haskell在haskell中返回不同的类型
【发布时间】:2013-10-30 14:53:12
【问题描述】:

我对 Haskell 有点陌生,正在做一个项目,我有以下代码:

data Nested a = Elem a | Nested [Nested a] deriving (Eq, Show)
data Symbol a = Value a | Transformation (a -> a -> a) deriving (Show)


toSymbol :: [Char] -> Nested (Symbol Integer)
toSymbol x  
|all isDigit x = Elem (Value (strToInt x))
|x == "+" = Elem (Transformation (\x y -> x + y))

有没有办法避免这个函数的类型被限制为嵌套(符号整数)?我想用 Symbol 来表示许多不同的类型,并有一个函数 toSymbol 类似于以下内容:

toSymbol x  
|x == "1" = Elem (Value 1)
|x == "+" = Elem (Transformation (\x y -> x + y))
|x == "exampleword" = Elem (Value "word")
|x == "concatenate()" = Elem (Transformation concatTwoStrings)

我不知道这样的函数的类型签名可能是什么。我能做些什么来获得类似的功能吗?

【问题讨论】:

  • 不,这只能通过完全绕过类型系统来工作。你想为这类东西使用动态语言。 Haskell 方法首先不是从字符串开始,而是从作为 DSL 的 Haskell 代码开始;然后编译器可以静态推断类型,并且您可以获得完整的类型安全性,而无需太多额外的语法。或者从某种自定义树 ADT 结构开始。但不是来自纯字符串!如果您需要将一些数据保存在文件中,there's libraries for that,但我不会打扰细节。

标签: haskell types


【解决方案1】:

您无法弄清楚类型签名的原因是因为您正在尝试“使函数的返回类型取决于传递的字符串的值,也就是依赖类型编程”,字符串仅在运行时可用。

所以基本上,如果您尝试说:toSymbol :: String -> Nested (Symbol a)a 取决于字符串的运行时值,这就是编译器抱怨它的原因。

有很多方法可以优化你的类型,以便所有部分组合在一起,一种可能的解决方案是使用一种新类型,它指定符号可能具有的不同类型的值。下面是例子:

data Nested a = Elem a | Nested [Nested a] deriving (Eq, Show)
data Symbol a = Value a | Transformation (a -> a -> a)
data SymbolType = SInteger Integer | SString String

addSymbols :: SymbolType -> SymbolType -> SymbolType
addSymbols (SInteger a) (SInteger b) = SInteger (a+b)
addSymbols _ _ = error "Not possible"

concatSymbols :: SymbolType -> SymbolType -> SymbolType
concatSymbols (SString a) (SString b) = SString (a++b)
concatSymbols _ _ = error "Not possible"

toSymbol :: String -> Nested (Symbol SymbolType)
toSymbol x  
  |x == "1" = Elem (Value (SInteger 1))
  |x == "+" = Elem (Transformation addSymbols)
  |x == "exampleword" = Elem (Value (SString "word"))
  |x == "concatenate()" = Elem (Transformation concatSymbols)

【讨论】:

    【解决方案2】:

    我认为不可能编写一个函数来做到这一点。一种可能的解决方案是使用类型类,它保持单一功能 API:

    {-# LANGUAGE FlexibleInstances #-}
    
    ...
    
    class Token a where
        toSymbol :: String -> Nested a
    
    instance Token (Symbol Integer) where
        toSymbol x
            |all isDigit x = Elem (Value (read x))
            |x == "+" = Elem (Transformation (\x y -> x + y))
            |otherwise = error "Wrong type"
    
    instance Token (Symbol String) where
        toSymbol "exampleword" = Elem (Value "word")
        toSymbol "concatenate()" = Elem (Transformation (++))
        toSymbol _ = error "Wrong type"
    

    【讨论】:

      猜你喜欢
      • 2021-12-01
      • 1970-01-01
      • 2010-12-04
      • 2013-05-09
      • 1970-01-01
      • 2018-11-27
      • 1970-01-01
      • 1970-01-01
      • 2019-06-06
      相关资源
      最近更新 更多