代码之家  ›  专栏  ›  技术社区  ›  mb14

导入haskell序曲中已经定义的东西的正确方法

  •  15
  • mb14  · 技术社区  · 15 年前

    我试图在haskell中定义一个可折叠的实例,但在导入方面有一些问题。

    所以先试试: 模块MyLIST 在哪里?

    import Data.Foldable
    
    data MyList a = MyList [a]
    
    instance Foldable (MyList) where
      foldr f b (MyList as) = foldr f b as
    

    结果(正常但烦人)

    “folder”出现不明确

    所以,我想我得把它藏起来,不让序曲出现: 模块MyLIST 在哪里?

    import Prelude hiding (foldr)
    import Data.Foldable
    
    data MyList a = MyList [a]
    
    instance Foldable (MyList) where
      foldr f b (MyList as) = foldr f b as
    

    这个编译,我加载到ghci并尝试一些基本的东西:

    *MyList> foldr (:) "" (MyList "hello")
    "hello"
    *MyList> foldl (flip (:)) "" (MyList "hello")
    
    <interactive>:1:0:
        Ambiguous occurrence `foldl'
        It could refer to either `Prelude.foldl', imported from Prelude at MyList.hs:4:0-28
                              or `Data.Foldable.foldl', imported from Data.Foldable at MyList.hs:5:0-19
    *MyList>
    

    所以Foldr行,但Foldl不行。我的第一个问题是

    我需要手动隐藏数据中定义的每个方法吗?从序曲中折叠是一种很好的方法吗?

    .

    为了避免这个问题,我尝试进行合格的导入: 模块MyLIST 在哪里?

    import qualified  Data.Foldable as F
    
    data MyList a = MyList [a]
    
    instance F.Foldable (MyList) where
      foldr f b (MyList as) = foldr f b as
    

    似乎是用GHC编译的,但是

    *MyList> foldr (:) "" (MyList "hello")
    
    <interactive>:1:14:
        Couldn't match expected type `[Char]'
               against inferred type `MyList Char'
        In the third argument of `foldr', namely `(MyList "hello")'
        In the expression: foldr (:) "" (MyList "hello")
        In the definition of `it': it = foldr (:) "" (MyList "hello")
    

    找不到folder,但很有可能f.folder在ghci工作。

    *MyList> F.foldr (:) "" (MyList "hello")
    "hello"
    

    但仅在ghci中,如果我尝试导入文件中的mylist,folder、f.folder、mylist.f.folder和mylist.folder将不起作用。

    为什么它在GHCI中有效,但在现实中无效?

    我想我必须导入数据。可再次折叠(在使用我的列表的每个文件中)

    有没有更好的方法(比如导出数据。可在MyList中折叠)?

    (我是哈斯克尔大学的新生,尤其是在模块方面)


    经过几次反应,似乎没有一个干净的解决方案来解决这个问题。不过,我很肯定我不是第一个这么做的,所以

    处理这种问题的常见做法是什么?

    谢谢你的帮助。

    5 回复  |  直到 11 年前
        1
  •  2
  •   Blaisorblade    11 年前

    这里是Thomas Eding解决方案的一个变体,类型较少。基本上,您可以导入(在序曲中)隐藏一些函数的序曲,然后重新导出序曲;这将导出减去这些函数的序曲。此技术通常用于编写前端模块,只在库中重新导出某些函数。

    然后你也可以再出口 Data.Foldable .

    在这里,我用等价物替换了一些前奏函数(例如 Foldable Category )

    module Prelude2 (module Prelude, module Data.Foldable, module Control.Category) where
    
    import Prelude hiding (id, (.), foldr)
    import Data.Foldable (Foldable, foldr) -- You might want to import everything.
    import Control.Category (Category((.), id))
    -- Try out replacing with:
    -- import Control.Category ()
    -- to see that no (.) is available.
    

    用途:

    module Foo where
    import Prelude()
    import Prelude2
    

    也就是说,注意 foldr (.) 在里面 Foo 如GHCI所示:

    $ ghci Foo.hs
    GHCi, version 7.6.3: http://www.haskell.org/ghc/  :? for help
    Loading package ghc-prim ... linking ... done.
    Loading package integer-gmp ... linking ... done.
    Loading package base ... linking ... done.
    [1 of 2] Compiling Prelude2         ( src-lib/Prelude2.hs, interpreted )
    [2 of 2] Compiling Foo              ( /Users/pgiarrusso/AeroFS/Repos/pts-bluevelvet/src-lib/Foo.hs, interpreted )
    Ok, modules loaded: Foo, Prelude2.
    *Foo> :t foldr
    foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
    *Foo> :t (.)
    (.) :: Category cat => cat b c -> cat a b -> cat a c
    *Foo>
    

    如果你尝试替换的建议

     import Control.Category ()
    

    GHCI会告诉你 () 在中完全没有定义 :

    *Foo> :r
    [1 of 2] Compiling Prelude2         ( src-lib/Prelude2.hs, interpreted )
    [2 of 2] Compiling Foo              ( /Users/pgiarrusso/AeroFS/Repos/pts-bluevelvet/src-lib/Foo.hs, interpreted ) [Prelude2 changed]
    Ok, modules loaded: Foo, Prelude2.
    *Foo> :t (.)
    
    <interactive>:1:1: Not in scope: `.'
    
        2
  •  7
  •   Simon Marlow    15 年前

    为什么它在GHCI中有效,但在现实中无效?

    因为在您的ghci会话中,您在 MyList 模块,所以 F.foldr 在范围内,但如果导入 我的名单 到另一个模块中,然后只有导出的名称 我的名单 以及您导入的其他模块都在作用域中。

    你的猜测是正确的-在每个模块中使用 Data.Foldable.foldr 你必须

    import qualified Data.Foldable as F
    

    模块导出的名称是不合格的;这些名称的限定性在模块导入时决定。

    多年来,有人提议允许出口合格的名称,但迄今为止没有实施任何措施。

        3
  •  6
  •   Ionuț G. Stan    15 年前

    关于内隐 Prelude 导入,您可以添加以下语言杂注,然后从 序曲 但它可能比简单地把东西藏起来 序曲 或使用 Data.Foldable .

    {-# LANGUAGE NoImplicitPrelude #-}
    
    import Prelude (someFunction)
    

    为什么会变得更丑?因为您可能需要导入被认为是理所当然的数据类型和函数,甚至是代码中未显式使用的函数:

    {-# LANGUAGE NoImplicitPrelude #-}
    module Main (main) where
    
    -- we import fromInteger although it's not explicitly used
    import Prelude (Int, foldl, fromInteger, (+), putStrLn, (.), ($), IO, show)
    
    sum :: [Int] -> Int
    sum = foldl (+) 0
    
    main :: IO ()
    main = putStrLn . show $ sum [1,2,3]
    

    我告诉过你这不是因为这是一个很好的解决方案,而是为了知道有这样一件事。

        4
  •  2
  •   Thomas Eding    15 年前

    你可以做一个 Prelude' 只导出所需内容的模块。然后,您可以按如下方式开始您的实际模块:

    import Prelude ()
    import Prelude'
    import Data.Foldable
    

    当然你必须在 前奏曲 但至少它是可重用的。

    澄清:

    前奏曲

    module Prelude' (
        id
      , Num (..)
      , everthing you want exported for your 'customized' prelude module goes in this list
      ) where
    
        5
  •  2
  •   Ionuț G. Stan    15 年前

    我已经重新阅读了你的问题和一些评论,我想你最接近你想要的是这样的:

    module MyList
      (
        module Data.Foldable,
        MyList(..)
      )
    where
    
    
    import Data.Foldable
    import Prelude (($))
    
    
    data MyList a = MyList [a]
    
    instance Foldable (MyList) where
        foldr f b (MyList as) = foldr f b as
    

    基本上, MyList re-exports 这个 Data.Foldable 模块,以便使用模块的人不必导入数据。可再次折叠,但…她必须隐藏一些功能 Prelude .

    module Main (main) where
    
    
    import Prelude hiding (foldr)
    import MyList
    
    
    mySum :: MyList Int -> Int
    mySum = foldr (+) 0
    
    main :: IO ()
    main = putStrLn . show . mySum $ MyList [1,2,3]
    

    嗯,这是件好事。您不应该决定某人如何以及在他自己的模块中导入什么。

    推荐文章