Home Php C# Sql C C++ Javascript Python Java Go Android Git Linux Asp.net Django .net Node.js Ios Xcode Cocoa Iphone Mysql Tomcat Mongodb Bash Objective-c Scala Visual-studio Apache Elasticsearch Jar Eclipse Jquery Ruby-on-rails Ruby Rubygems Android-studio Spring Lua Sqlite Emacs Ubuntu Perl Docker Swift Amazon-web-services Svn Html Ajax Xml Java-ee Maven Intellij-idea Rvm Macos Unix Css Ipad Postgresql Css3 Json Windows-server Vue.js Typescript Oracle Hibernate Internet-explorer Github Tensorflow Laravel Symfony Redis Html5 Google-app-engine Nginx Firefox Sqlalchemy Lucene Erlang Flask Vim Solr Webview Facebook Zend-framework Virtualenv Nosql Ide Twitter Safari Flutter Bundle Phonegap Centos Sphinx Actionscript Tornado Register | Login | Edit Tags | New Questions | 繁体 | 简体


10 questions online user: 39

0
votes
answers
9 views
+10

Haskell中的遞歸標記器

3

我在Haskell中工作,爲測試做準備。當前任務要求按以下公式標記字符串: 運行「tokenize str separate remove」時,應該輸出一個字符串列表。出現在字符串「分開」中的「str」中的每個字符應該是一個字符的字符串。出現在「刪除」字符串中的「str」中的每個字符應該被刪除。不分開或刪除的字符應該捆綁在一起。Haskell中的遞歸標記器

實施例顯示,

tokenize "a + b* 12-def" "+-*" " " 

應該輸出

["a", "+", "b", "*", "12", "-", "def"] 

下面

tokenize :: String -> String -> String -> [String] 
tokenize [] _ _ = [] 
tokenize [x] _ _ = [[x]] 
tokenize (x:xs) a b  | x `elem` a = [x] : tokenize xs a b 
         | x `elem` b = tokenize xs a b 
         | otherwise = (x:head rest) : tail rest 
           where 
             rest = tokenize xs a b 

它工作在一定程度上,這個問題是它的運營商在例如我當前的代碼與之前的信件捆綁在一起。

這樣

["a+","b*","12-","def"] 

儘管運營商在不同的字符爲。

+2

問題出在''|否則=(x:頭部休息):尾部休息,無論「頭部休息」是什麼,你都在'頭部休息'上放置'x'。 – sjakobi

沙发
0
1

首先,tokenize [x] _ _可能不是你想要的,因爲tokenize "a" "" "a"最後應該是["a"],應該是[]。其次,請勿撥打分隔符和清除列表String s。他們只是[Char] s。下面沒有區別,因爲type String = [Char],但同義詞的意義在於使語義含義更清晰,而且您沒有真正使用String s,因此您的功能不值得。此外,您應該將參數洗牌爲tokenize seps rems str,因爲這會使咖啡更容易。最後,您可能希望使用Data.Set而不是[Char],但我不會在此處使用它來保持接近該問題。

問題本身是| otherwise = (x:head rest) : tail rest,它將任何非特殊字符粘到下一個標記上,即使該標記應該是分隔符。在你的情況下,一個例子是當head rest = "+"x = 'a',你加入他們,所以你有"a+"。你需要進一步保護。

(另外:你的縮進搞砸:where條款綁定到整個方程,所以它的整個所有的衛兵看到它應縮進,使得很清楚。)

tokenize :: [Char] -> [Char] -> String -> [String] 
tokenize _ _ "" = [] 
tokenize seps rems (x:xs) 
    | x `elem` rems      = rest 
    | x `elem` seps      = [x]:rest 
    -- Pattern guard: if rest has a single-char token on top and that token is a sep... 
    | ([sep]:_) <- rest, sep `elem` seps = [x]:rest 
    -- Otherwise, if rest has a token on top (which isn't a sep), grow it 
    | (growing:rest') <- rest   = (x:growing):rest' 
    -- Or else make a new token (when rest = []) 
    | otherwise       = [x]:rest 
    where rest = tokenize xs seps rems 

您可能也用filter

tokenize seps rems = tokenize' . filter (not . flip elem rems) 
    where tokenize' "" = [] 
     tokenize' (x:xs) 
      | x `elem` seps      = [x]:rest 
      | ([sep]:_) <- rest, sep `elem` seps = [x]:rest 
      | (growing:rest') <- rest   = (x:growing):rest' 
      | otherwise       = [x]:rest 
      where rest = tokenize' xs 
0
votes
answers
15 views
+10

創建Set數據類型

-2

所以我需要在Haskell中創建一個Set數據類型。創建Set數據類型

所以,我的問題的第一部分,我需要定義

type Set a = ... 

我把它設置爲

type Set a = Set [a] 

因爲套裝也只是α的名單,對不對? 或者,將正確的方式做到這一點是

type Set a = ([a]) 

然後,在接下來的一部分,我需要實現的功能

setSuchThat :: (a -> Bool) -> (Set a) 

功能需要一個特徵函數f並返回一組這樣僅當f(x)爲真時,值x(適當類型)纔在該集合中。因此,它在使用中的例子是,

setSuchThat (x -> x == "coke") 

所以我的問題是,現在,是該函數我基本上需要評估該功能讓「可樂」,然後將其添加到我的設置。我想我只是不明白,在這個功能中,我會去做這件事。

+0

查找'filter'的源代碼。你會發現'setSuchThat = filter'。 – Alec

+1

這將是不可能的。有無數的可能的字符串。程序如何知道它具有所有返回「真」的值?更現實的解決方案是使用'filter'。 – 4castle

+1

如果你唯一需要實現的功能是'setSuchThat',那麼讓我建議'輸入Set a = a - > Bool'。你應該找到'setSuchThat'這個微不足道的東西。 –

沙发
0
4

繼丹尼爾·瓦格納的建議,你可以定義一組作爲謂語指示元素是否在集合:

type Set a = a -> Bool 

良好的措施,我將使用一個newtype,以使其更清晰這裏我們使用集:

newtype Set a = Set { contains :: a -> Bool } 

然後setSuchThat只是包裝一個謂語Set

setSuchThat :: (a -> Bool) -> Set a 
setSuchThat = Set 

您可以使用contains功能的一組測試成員:

> setSuchThat (== "coke") `contains` "coke" 
True 

> setSuchThat (== "coke") `contains` "pepsi" 
False 

所以空集只是setSuchThat (const False) - 對於任何給定的元素,它總是回答這個問題:「請問一套包含此元素?「 沒有」。

insert :: (Eq a) => a -> Set a -> Set a 
insert x s = Set $  x' -> x == x' || s `contains` x' 

> insert "pepsi" (setSuchThat (== "coke")) `contains` "pepsi" 
True 

union其他功能很容易:

然後你就可以實現諸如insert組成現有contains功能與新的功能擴展集新元素

union :: Set a -> Set a -> Set a 
union s1 s2 = Set $  x -> s1 `contains` x || s2 `contains` x 

> let sodas = setSuchThat (== "coke") `union` setSuchThat (== "pepsi") 

> sodas `contains` "coke" 
True 

> sodas `contains` "pepsi" 
True 

> sodas `contains` "water" 
False 

作爲練習,請嘗試執行其他設置功能,如delete,intersectdifference

此方法的一個缺點是每個查找都是線性-O(n) - 插入或刪除元素的數量。此外,你不能簡單地枚舉集將其轉換爲A的所有元素列表中,你只能列舉測試每一個是否是一個元素。不過,其中一個的優勢就是讓您輕鬆表示無限集;例如,setSuchThat (> 0)包含所有非負數。

這就是爲什麼標準Data.Set類型使用基於樹的數據結構,而不是功能,代表元素,它們的實際值。用這種方法,值可在不增加集的大小被刪除,並且,因爲它使用Ord代替Eq,實現了更有效的對數O(log n)的-lookups和插入。

板凳
0
1

要建立在什麼Jon Purdy打下了:

你需要考慮的Set a = a -> Bool的作爲,你必須一起工作的限制。當您看到setSuchThat :: (a -> Bool) -> (Set a)時,您可以將其讀取爲與setSuchThat :: (Set a) -> (Set a)setSuchThat :: (a -> Bool) -> (a -> Bool)相同。 setSuchThat有點像一個mcguffin,它只是在那裏使用更清晰的功能 - 這是沒有必要的。你正在做

一切都是以功能f並將其應用到變量x。的setSuchThat整個的一點是要傳遞fx只有f x返回。

0
votes
answers
32 views
+10

靜態鏈接二進制文件中缺少調試符號

5

我正在使用堆棧構建靜態鏈接二進制文件,並嘗試向其添加調試符號(以下內容:https://downloads.haskell.org/~ghc/master/users-guide/debug-info.html)。但是GDB報告:no debugging symbols found靜態鏈接二進制文件中缺少調試符號

我缺少什麼?

我已經加入到ghc-options.cabal file-g -rtsopts並向ld-options-static

stack install  
    --install-ghc  
    --split-objs  
    --ghc-options="-fPIC -fllvm -pgmlo opt -pgmlc llc" 

GDB被調用如下::gdb --args nodebug-exe +RTS -V0

GHC 8.2.1

所有源代碼是在這裏:我使用堆棧使用下面的命令建立https://github.com/carbolymer/haskell-missing-debug-symbols

+1

也許加上--no-strip? '--no-strip:在庫,可執行文件等中爲所有表達式禁用DWARF調試符號剝離# – Zpalmtree

+0

@Zpalmtree,沒錯。我應該看看'stack install --help' ...你可以添加它作爲答案。 – carbolymer

沙发
0
5

--no-strip防止調試信息在棧構建中被刪除。

documentation

堆棧現在支持調試和分析與DWARF信息, 使用--no條,--no庫剝離,和 --no可執行剝標誌來禁用從編譯的庫和可執行文件中刪除這些信息的默認行爲。

0
votes
answers
11 views
+10

如何合併兩個字符串我Haskell並返回一個新的字符串

-3

如何合併兩個字符串。例如,我有兩個列表
["me","you","he"]["she","they","it"]。我想要形成一個新的列表,其中每個對應的字符串組合在一起,如 ["meshe","youthey","heit"]。現在的問題是:我怎麼能合併兩個字符串如何合併兩個字符串我Haskell並返回一個新的字符串

+0

也可以'結合xs ys = [x ++ y | (x,y)< - zip xs ys]' – RoadRunner

沙发
0
5
combine = zipWith (++) 

zipWith需要兩個列表,並應用於給兩個列表的第一個項目,然後是第二等的功能。如果一個表比其他長,其額外項目將被跳過。

++函數帶兩個列表並將它們連接在一起。一個字符串只是一個字符列表。

"hello " ++ "world" == "hello world"

用法:

λ> combine ["me","you","he"] ["she","they","it"] 
["meshe","youthey","heit"] 
λ> combine [] [] 
[] 
λ> combine ["me", "you"] ["she"] 
["meshe"] 
λ> 

++操作是很基本的,所以你可能會更好繼續讀你來之前計算器正在使用的任何學習材料,你就會有我期望的很多問題都會在你的書中得到解答。

如果你不想使用zipWith,你可以很簡單地用遞歸寫像這樣:

combine [] _ = [] 
combine _ [] = [] 
combine (x:xs) (y:ys) = (x ++ y) : combine xs ys 

用法和以前一樣。

+0

如果不想使用zipwith函數 –

+0

@UmairAziz請參閱我的編輯。這是一個非常簡單的遞歸函數。 – Zpalmtree

+0

@UmairAziz你爲什麼不呢?作爲一般規則,您應該儘量避免顯式遞歸;這是您重塑車輪的標誌。 – chepner

0
votes
answers
29 views
+10

在safeTail函數中的Haskell模式匹配

-3

我得到了一個使用模式匹配定義的Haskell函數,但我不是很明白爲什麼它看起來像它的樣子。在safeTail函數中的Haskell模式匹配

safeTail (x : xs) = xs 

我不是特別明白在(x:xs),這是什麼意思?

+0

如果是這樣的功能的完整定義,我會已命名爲'unsafeTail'或'dangerousTail',因爲這將在空列表中崩潰。 – chi

+0

我得到了空列表的catchall,但決定不把它放在這裏,因爲這裏的重點是我不明白(x:xs)的語法而不是函數。 – Wandy

沙发
0
1

那就是模式匹配。

函數safeTail的第一個參數是一些列表類型。如果參數是非空列表,則此模式匹配將成功並將x綁定到head元素,將xs綁定到列表的尾部。

如果您將空列表傳遞給safeTail,則模式匹配將失敗,並檢查其他模式(如果存在)。

板凳
0
2

考慮列表數據類型的類似定義。

data List a = Empty | Cons a (List a) -- (1) 

有兩個構造函數:一個用於創建一個空列表,另一個用於創建一個給定值和另一個列表的列表。

模式匹配通過將值與用於創建它的構造函數進行匹配來工作。

safeTail (Cons x xs) = xs -- (2) 

也就是說,如果safeTail被施加到使用Cons構造定義的值,則返回值是第二個參數Cons

在實際的代碼,這兩個類型構造ListEmpty數據構造被命名爲[]Cons構造被命名爲(:)

data [] a = [] | (:) a ([] a) 

其中的Haskell允許以特殊語法

data [a] = [] | a : [a] 

應用類型建築工[]的類型或類型變量被寫入可以通過包括[]內部的參數,和所述符號構造器(代替因爲它以:開頭)可以用作中綴運算符。

也就是說,可以編寫

safeTail ((:) x xs) = xs -- (3) 

safeTail (x : xs) = xs -- (4) 

與(2),(3),和(4)等效於上述(1)。

>>> safeTail ((:) 3 ((:) 2 ((:) 1 []))) 
[2,1] 
>>> safeTail (3:2:1:[]) 
[2,1] 
>>> safeTail [3,2,1] 
[2,1] 

爲了進一步簡化,Haskell中表示(x:[])[x](x:y:[])[x,y]作爲等

safeTail一個完整的定義也將一個空的list參數提供一個值:

safeTail [] = [] 

Maybe基於定義

safeTail :: [a] -> Maybe [a] 
safeTail [] = Nothing 
safeTail (x:xs) = Just xs 
+0

基於'Maybe'的定義實際上是一個'safeHead'而不是'safeTail' – 4castle

0
votes
answers
17 views
+10

爲什麼不hSetBuffering返回一個新的句柄,而不是改變給定的句柄?

3

在Haskell中,我們試圖通過不改變變量或傳遞參數來以不可變的方式編寫大部分代碼,而是通過所需的更改從舊的創建新值。爲什麼不hSetBuffering返回一個新的句柄,而不是改變給定的句柄?

main = do 
withFile "something.txt" ReadMode (handle -> do 
    hSetBuffering handle $ BlockBuffering (Just 2048) 
    contents <- hGetContents handle 
    putStr contents) 

那麼是什麼原因比hSetBuffering,這需要一個手柄,並將其緩衝模式的功能,改變了傳遞的handle本身,而不是用所需的緩衝模式返回一個新手柄?

+3

對於您只能讀取緩衝區,這可能是好的,但有兩個手柄,以具有獨立的緩衝器一樣可寫的對象聽起來像瘋狂的良方。 –

沙发
0
6

對於常規的Haskell值,保留值的舊版本沒有問題。但是,Handle是對操作系統分配的可變資源的引用,以及進位狀態。在調用hSetBuffering版本後返回新的Handle版本後,之前版本的Handle版本仍然存在?他們應該反映這種變化嗎?如果答案是肯定的,那麼hSetBuffering的新句柄返回版本就有點謊言了。

如果類型系統以某種方式不允許在調用該函數後保留舊版本的Handle,那麼hSetBuffering的這個新的句柄返回版本可以工作。它可以通過強制執行一個約束來實現:接收Handle作爲參數的函數只能使用該參數單一時間,而像dup :: Handle -> (Handle,Handle)這樣的「複製」句柄的函數不允許使用

有一個(尚未被接受的)proposal擴展Haskell執行這些限制的能力。事實上,文件操作是其中一個激勵性的例子。從本文的第2.3節:

type File 
openFile :: FilePath → IOL 1 File 
readLine :: File ? IOL 1 (File,Unrestricted ByteString) 
closeFile :: File ? IOL ω() 

根據這項建議,我們只能有一個File的單一版本,在任何給定時間左右。 closeFile使得對File的引用不可用,因此我們無法關閉已經關閉的文件。每個讀取操作都採用先前版本的File,並隨讀取的數據一起返回一個新的操作。而hSetBuffering將有一個類型,如:

hSetBuffering :: BufferingMode -> File ? IOL 1 File 
+0

感謝您的詳細解釋。 – sidoshi

0
votes
answers
11 views
+10

哈希克爾派生和實例之間的區別

2

我有一個類型,我已經做了Show類的實例,但我沒有得到期望的結果。如果我嘗試使用deriving字,然後它工作,使之秀類的實例,但如果嘗試像:哈希克爾派生和實例之間的區別

instance Show (SomeValue v) where 
    show (Null) = "You have no value" 
    show (Justs v) = show (Justs v) 

findKey key = foldr ((k,v) acc -> if key == k then Justs v else acc) Null 

它去在未結束循環(種)。我認爲,通過使用deriving單詞得到的默認實現工作,上面的代碼有什麼問題?它編譯但它不打印任何東西。

是否有可能我打印這樣的值:(沒有「Justs」)?

instance Show (SomeValue v) where 
    show (Null) = "You have no value" 
    show (Justs v) = show (v) 
+0

相關:https://stackoverflow.com/questions/28665917/accessing-the-default-show-in-haskell –

+0

@WillemVanOnsem它不一樣。對於我的數據構造函數,我只有兩個值,對於這兩個值我已經定義了show,但它不打印任何東西,我甚至嘗試使用type-annotations進行讀取,但它不起作用:) –

+0

當然,它確實不打印任何東西,它被卡在無限循環中。 –

沙发
0
3

代碼

show (Justs v) = show (Justs v) 

進入一個無限循環出於同樣的原因

f x = f x 

一樣。

你可以把它寫不Justs爲你問,你只需要一個約束的情況下


instance (Show v) => Show (SomeValue v) where 
    show Null = "You have no value" 
    show (Justs v) = show v 

,因爲如果你要儘量表現出vv應該showable,不是嗎?

0
votes
answers
18 views
+10

Nix頻道和GHC/Hackage包版本

2

我目前正在通過Gabriel's tutorialNix和Haskell上工作。Nix頻道和GHC/Hackage包版本

在尼克斯有channels和它們所包含 (類似棧LTS版本) 策展組Hackage包和GHC編譯器。

對於每個 LTS版本Stackage顯示了每個Hackage包的GHC編譯器版本和版本號 。在我開始使用頻道之前,我可以在哪裏查找nix頻道的這些信息?

沙发
0
0

對於Haskell軟件包的版本,我找到了一個答案:有像https://raw.githubusercontent.com/NixOS/nixpkgs/release-16.09/pkgs/development/haskell-modules/hackage-packages.nix這樣的文件。這些文件是不是真的好用...

編輯

在這個文件中,我可以 搜索= "base"那麼我就可以找到base庫的版本。 從基礎庫的版本我可以GHC版本lookup

這給下表:

newest -> base-4.10.0.0 -> GHC 8.2.1 
17.09 -> base-4.10.0.0 -> GHC 8.2.1 
17.03 -> base-4.9.1.0  -> GHC 8.0.2 
16.09 -> base-4-9.0.0  -> GHC 8.0.1 
16.03 -> base-4.8.2.0  -> GHC 7.10.3 
15.09 -> base-4.8.2.0  -> GHC 7.10.3 

但是一個簡單的方法將是不錯...

0
votes
answers
28 views
+10

如何使用堆棧來安裝本地創作的Haskell模塊以實現全局使用?

1

我有一個本地創作Haskell的項目,這既產生:如何使用堆棧來安裝本地創作的Haskell模塊以實現全局使用?

  1. 二進制可執行文件,
  2. 幾個新的哈斯克爾模塊,我想發到我的其他訪問,哈斯克爾基礎,可執行文件。

後:

stack build 
stack install 

我發現:

  1. 二進制可執行文件(#1,以上)運行在任何目錄下就好了。
  2. 但是,新的Haskell模塊(上面#2)只有在我從我的項目目錄中運行時才能找到! (也就是說,對於除#1以外的任何可執行文件)。

我需要能夠從任何地方找到新模塊。 我該如何做到這一點?

+0

聽起來和[這個問題只有幾個小時前]類似(https://stackoverflow.com/questions/47989939/is-there-a-declarative-way-to-specify-packages-to-be-installed- into-global-proje),在那裏我建議你使用Cabal-install而不是stack,那麼你永遠不需要擔心模塊安裝是全局的。 – leftaroundabout

+0

感謝您的評論。是的,「cabal install」確實解決了我的問題。然而,現在我已經有了兩個單獨的,並行的,大部分冗餘的Haskell設備來啃硬盤空間,這看起來非常浪費和不必要。這尤其令人憤慨,因爲我生產的二進制可執行文件可以在任何目錄下運行,這意味着它知道如何從我的系統的任何地方(因爲它導入它們)找到我的新Haskell模塊。那麼,爲什麼我不能讓這些新模塊可用於其他Haskell可執行文件呢? – dbanas

+0

這絕對是不必要的,這就是爲什麼我在我的筆記本電腦上只使用_only_ Cabal-install,而僅使用Travis的Stack。 - 請注意,您的可執行文件找到導入模塊的方式與編譯器爲源文件找到它們的方式有很大不同。事實上,如果你靜態鏈接,那麼就不需要找到任何外部的東西,因爲一切都已經包含在二進制文件中了。如果您動態鏈接,它會查找特定散列動態庫文件的硬編碼路徑,但這隻適用於版本解析程序和鏈接程序在完成之前完成其工作。 – leftaroundabout

沙发
0
1

每個堆棧項目位於其自己的沙箱中,因此編譯的模塊只能在該項目中使用。編譯的依賴項(來自堆棧快照)有時會在項目之間共享。

請注意,您可以在軟件包列表中列出相對路徑,並指向該軟件包。它會重新構建,但可以通過這種方式直接在另一個項目中使用。爲什麼多餘的建築? Stack與Cabal-install有不同的項目模型 - 它不允許包DB的變化影響其他項目的構建。

共享這樣一個包的一個選擇是讓它在git倉庫中使用https://docs.haskellstack.org/en/stable/custom_snapshot/,但這些東西還是有點新的。

+0

感謝您的迴應。所以,如果我理解你在說什麼,那聽起來像爲Haskell可執行文件構建的模塊,使用動態插件的自定義風格,並不適合用堆棧構建/安裝。相反,它們應該用cabal製造/安裝。這是一個公平的總結嗎? – dbanas

+0

哦,我沒有意識到你正在嘗試動態加載模塊。如果您在項目中執行「堆棧生成pkg-x」,那麼這些模塊將在由'stack exec'設置的GHC_PACKAGE_PATH指定的包DB中可用。這聽起來像你想要更多的全球共享,但考慮到動態插件的工作,依賴版本需要排隊,所以它應該在一個堆棧項目內完成...... 不,你可能不應該使用cabal for這個。很確定新構建的東西實際上會讓這個更笨拙,因爲你需要指定一個特定的軟件包編號 – mgsloan

+0

謝謝!我想確保我明白了:所以,我真正需要做的是在將新的自定義插件添加到其堆棧項目描述之後,重新生成此「外部」可執行文件。是對的嗎?換句話說,嘗試構建可執行文件,使用一個堆棧項目和插件,使用不同的堆棧項目,這是一種固有的缺陷。如果這是正確的,那麼潛在的插件開發人員似乎非常脆弱和限制。我認爲這是一個設計良好的/有記錄的API(可執行文件)旨在防止的。我必須在這裏錯過一些基本的東西。 – dbanas

0
votes
answers
13 views
+10

比較Haskell中兩個項的構造函數的一般方法

4

給定某個數據類型的兩個項t1 t2,是否有某種方法可以檢查t1和t2是否以相同構造函數開始,而不在構造函數中進行窮舉或模式匹配?就像如果我喜歡的類型要麼是B,那麼我想比較Haskell中兩個項的構造函數的一般方法

checkConst (Left x) (Left y) = True 
checkConst (Right x) (Left y) = False 
... 

等實際上不這樣做,模式匹配,並在某種程度上是普遍適用於其他類型的用10層構造的順序。有沒有一個很好的方法來做到這一點?

+0

也許你可以使用[鏡頭包]中的[Pri??sms](https://hackage.haskell.org/package/lens-4.15.4/docs/Control-Lens-Prism.html)(https: //hackage.haskell.org/package/lens-4.15.4),可能值得一試。 –

沙发
0
6

您可能正在尋找Data.Data模塊中提供的泛型功能。如果你定義一個派生Data實例的數據類型,例如:

{-# LANGUAGE DeriveDataTypeable #-} 
import Data.Data 
data Foo = Bar1 Int 
     | Bar2 String String 
     | Bar3 Double 
     deriving (Data) 

那麼你就可以toConstr檢索一個值的構造:

> toConstr (Bar1 1) 
Bar1 
> toConstr (Bar2 "hello" "there") 
Bar2 
> 

這些都是可以Constr類型的值平等比較,這樣你就可以定義:

checkConst :: (Data g) => g -> g -> Bool 
checkConst x y = toConstr x == toConstr y 

,並得到:

> checkConst (Bar1 10) (Bar1 20) 
True 
> checkConst (Bar1 10) (Bar3 20) 
False 
> 
板凳
0
3

您可以使用某種中間類型,它可以唯一地區分每個構造函數並具有一個Eq實例。例如,您可以使用Int來區分每個數據構造函數,然後比較這些值。

checkConst x y = toInt x == toInt y 
    where 
    toInt (Left _) = 1 :: Int 
    toInt (Right _) = 2 

如果你的類型實現了從Data.DataData,你可以使用toConstr使用Constr爲您的中間類型。在Either的情況下,這不是必需的,因爲您可以使用isRight x == isRight y,但對於具有10個構造函數的數據類型,這將更清晰。