理解一个Haskell类型歧义的例子 [英] Understanding a case of Haskell Type-Ambiguity

查看:127
本文介绍了理解一个Haskell类型歧义的例子的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



该程序应该:


  • 获取命令行参数

  • 将标记化参数连接回单个字符串

  • 字符串读入 NestedList 数据类型
  • NestedList 展平成列表

  • 列印 List



  • 不幸的是,由于类型不明确, p>

    Haskell代码:
    $ b

      { -  
    运行如下:
    $ ./prog List [Elem 1,List [Elem 2,List [Elem 3,Elem 4],Elem 5]]
    输出:[1,2,3 ,4,5]
    - }
    import System.Environment
    import Data.List

    data NestedList a = Elem a | List [NestedList a]
    derived(Read)

    main = do
    args< - getArgs
    print。扁平化。 read $ intercalateargs

    flatten :: NestedList a - > [a]
    flatten(Elem x)= [x]
    flatten(List x)= concatMap flatten x

    编译错误:

      prog.hs:8:21: 
    由于在prog.hs:8:21-24
    (显示a0)中使用`read'而产生的约束中的
    (读取a0)不明确的类型变量`a0'在prog.hs:8:3-7处使用`print'
    可能的修复:添加修复这些类型变量的类型签名
    在'(。)'的第二个参数中,即`read'
    在'(。)'的第二个参数中,即'flatten。阅读'
    在表达式中:print。扁平化。阅读

    有人可以帮助我理解/为什么会出现类型歧义,以及如何编码明确的。

    解决方案

    当Haskell由于函数应用程序而使类型变量消失时,会出现模糊类型。你在这里找到的那​​个 read / show 是很常见的。这里有个问题:

    让我们试着读一个字符串,这个操作的类型是

      read :: Read a =>字符串 - > a 

    这样,如果我们给它一个字符串,我们只会得到一个类似于

     读取()::读取a => a 

    换句话说,类型系统还没有能够选择具体的类型---它只是知道,无论答案是什么,它必须是 Read able。



    问题是,如果我们回头并立即显示我们正在应用的功能

      show :: Show a => a  - >字符串

    它也没有完全指定类型 a 。合并它们给我们

      show(read()):: String 

    我们已经失去了所有机会来决定哪些中间类型应该是。



    由于这种模糊性,Haskell不允许使用这种表达式。你通过插入一个完全限制类型的函数来修复它。一个常用的方法是使用函数 asTypeOf

      asTypeOf :: a - > a  - > a 
    asTypeOf = const

    确保第一个和第二个参数具有相同的类型。

     > show(read()`asTypeOf`()):: String 
    ()

    在您的特定示例中,您需要确定 a 中的 NestedList a 。一个简单的方法是明确地将 flatten 的类型作为具体的类型。

     打印。 (flatten :: NestedList Int  - > [Int])。阅读$ concat args 


    I wrote a Haskell program and got a compile error I don't understand.

    The program should:

    • Get the command line arguments
    • Concatenate tokenized arguments back to a single String
    • Read the String into a NestedList data type
    • Flatten the NestedList into a List
    • Print the List

    Unfortunately, it won't compile because of a type ambiguity.

    Haskell Code:

    {-
      Run like this:
      $ ./prog List [Elem 1, List [Elem 2, List [Elem 3, Elem 4], Elem 5]]
      Output: [1,2,3,4,5]
    -}
    import System.Environment
    import Data.List
    
    data NestedList a = Elem a | List [NestedList a]
      deriving (Read)
    
    main = do
      args <- getArgs
      print . flatten . read $ intercalate " " args
    
    flatten :: NestedList a -> [a]
    flatten (Elem x) = [x]
    flatten (List x) = concatMap flatten x
    

    Compile Error:

    prog.hs:8:21:
        Ambiguous type variable `a0' in the constraints:
          (Read a0) arising from a use of `read' at prog.hs:8:21-24
          (Show a0) arising from a use of `print' at prog.hs:8:3-7
        Probable fix: add a type signature that fixes these type variable(s)
        In the second argument of `(.)', namely `read'
        In the second argument of `(.)', namely `flatten . read'
        In the expression: print . flatten . read
    

    Could someone help me understand how/why there is a type ambiguity and how I can make the code unambiguous.

    解决方案

    Ambiguous types occur in Haskell whenever a type variable disappears due to function application. The one you have here, read/show is common. Here's the problem:

    Let's try to read a string, this operation has the type

    read :: Read a => String -> a
    

    such that if we give it a string we'll just get a type that looks like

    read "()" :: Read a => a
    

    In other words, the type system has not yet been able to pick a concrete type---it simply knows that whatever the answer is it must be Readable.

    The problem is that if we turn back around and show this immediately we're applying a function

    show :: Show a => a -> String
    

    which also doesn't fully specify the type a. Combining them gives us

    show (read "()") :: String
    

    and we've lost all opportunities to decide upon what that intermediate type should have been.

    Due to this ambiguity, Haskell disallows such expressions. You fix it by somehow interjecting a function which completely constrains the type. A common method is to use the function asTypeOf

    asTypeOf :: a -> a -> a
    asTypeOf = const
    

    which ensures that the first and second arguments have the same type.

    > show (read "()" `asTypeOf` ()) :: String
    "()"
    


    In your particular example you need to determine what the a is in NestedList a. An easy method to doing that is to explicitly give the type of flatten as a concrete type.

    print . (flatten :: NestedList Int -> [Int]) . read $ concat args
    

    这篇关于理解一个Haskell类型歧义的例子的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆