2009-08-12 33 views
13

Tôi muốn viết mã mà sẽ đầu ra:Chuỗi suy trong Haskell

length [1,2,3] => 3 

Trong Ruby, tôi có thể làm điều đó thích:

puts "length [1,2,3] => #{[1,2,3].length}" 

Sau thử là Haskell thất bại ...

Prelude Data.List> print "length [1,2,3]" 
"length [1,2,3]" 
Prelude Data.List> print (length [1,2,3]) 
3 
Prelude Data.List> print "length [1,2,3]" (length [1,2,3]) 

<interactive>:1:0: 
    Couldn't match expected type `Int -> t' 
    against inferred type `IO()' 
In the expression: print "length [1,2,3]" (length [1, 2, 3]) 
In the definition of `it': 
     it = print "length [1,2,3]" (length [1, 2, 3]) 
Prelude Data.List> 
+8

BTW, sử dụng in trên một chuỗi sẽ in bằng dấu ngoặc kép (và thoát). Hãy thử putStr hoặc putStrLn để in chuỗi như là. –

Trả lời

15

Chuỗi thực sự chỉ là danh sách. Vì vậy, bạn có thể chuyển đổi số trở về từ chiều dài và gắn nó vào chuỗi khác của bạn với chức năng danh sách bình thường:

print $ "length [1,2,3] " ++ show (length [1,2,3]) 
3

Bạn có thể sử dụng một cái gì đó như

putStr "length [1,2,3] => " 
print (length [1,2,3]) 

EDIT:

Nếu bạn muốn làm điều đó như một chức năng, để vượt qua danh sách bất kỳ và viết chiều dài của nó, bạn có thể làm theo cách này:

print_length :: Show a => [a] -> IO() 
print_length xs = print ("length " ++ show xs ++ " => " ++ show (length xs)) 

Main> print_length [1,2,3,4,5] 
"length [1,2,3,4,5] => 5" 

Main> print_length [] 
"length [] => 0" 

Tất nhiên, như nhận xét ở trên, bạn có thể sử dụng putStrLn thay vì in.

+0

Có ba cách viết chúng trong một dòng không? – pierrotlefou

4

Hãy thử điều này trong ghci:

Prelude> :t print 
print :: (Show a) => a -> IO() 

Như bạn có thể thấy, print chức năng chỉ chấp nhận một đối số, trong khi mã ở trên được cung cấp hai.

Thay vào đó, hãy thử này:

putStrLn ("length [1,2,3] => " ++ show (length [1,2,3])) 

Nó tham gia vào hai chuỗi với ++ và sau đó in nó.

3

Ngoài ra những gì người khác nói bạn cũng có thể sử dụng toán tử bind monadic >> để kết hợp hai hành động IO:

putStr "length [1,2,3]: " >> print (length [1,2,3]) 

này tương đương với kết hợp chúng với do-ký hiệu:

do putStr "length [1,2,3]: " 
    print (length [1,2,3]) 
28

Trong khi các áp phích khác ở đây đề cập đến nhiều cách 'đúng' để thực hiện phép nội suy chuỗi, thì có cách sử dụng quasiquotation và interpolatedstring-perl6 library:

{-# LANGUAGE QuasiQuotes, ExtendedDefaultRules #-} 

import Text.InterpolatedString.Perl6 (qq) 

main = putStrLn [$qq| length [1,2,3] => ${length [1,2,3]} |] 

Trên thực tế, thư viện interpolatedstring-qq cung cấp cú pháp Ruby.

{-# LANGUAGE QuasiQuotes, ExtendedDefaultRules #-} 

import Text.InterpolatedString.QQ (istr) 

main = putStrLn [$istr| length [1,2,3] => #{length [1,2,3]} |] 

Điều đó nói rằng, có lẽ bạn nên chỉ cần sử dụng chương trình và ++ hoặc concat để keo cùng các dây

main = putStrLn $ "length [1,2,3] => " ++ show (length [1,2,3]) 

hoặc

main = putStrLn $ concat ["length [1,2,3] => ", show $ length (1,2,3)] 

Sau này có xu hướng trông đẹp hơn, số- khôn ngoan, khi bạn đang dán cùng nhau rất nhiều mảnh dây.

+0

Tại sao sử dụng 'concat' hoặc' ++' tốt hơn QuasiQuotes thì tốt hơn? –

+4

Mỗi khi bạn sử dụng mẫu-haskell trình biên dịch của bạn phải tải lên tại thời gian biên dịch tất cả các phụ thuộc của bạn. Nó có thể khá chậm. Tôi có xu hướng không phải chịu chi phí cho một sự tiện lợi nhỏ như nội suy chuỗi, khi thay thế gần như cùng độ dài và không yêu cầu tôi hoàn toàn tái cấu trúc mã của tôi khi quasiquotation xấp xỉ cú pháp Haskell mà tôi đang sử dụng không thể phân tích cú pháp một số cấu trúc cú pháp tôi cần. –

+0

@VladtheImpala, một lý do khác là mỗi QuasiQuoter yêu cầu người đọc phải hiểu một ngôn ngữ mới, vì vậy họ sẽ không nhất thiết có thể nhìn thấy lỗi ngay lập tức. Tôi chỉ sử dụng một QuasiQuoter nếu dự án của tôi sử dụng nó rất nhiều, và vì vậy tôi có thể mong đợi các nhà phát triển biết nó hoạt động như thế nào. – povman

28

Bạn cũng có thể chỉ cần sử dụng Text.Printf được bao gồm trong các thư viện cơ sở GHC:

> let format s = printf "length %s => %d\n" (show s) (length s) 
> format [1,2,3] 
length [1,2,3] => 3 

Có một số gói chuỗi suy trên Hackage http://hackage.haskell.org nếu bạn muốn tình huống fancier.

5

Sử dụng format chức năng từ text-format-simple thư viện:

import Text.Format 
format "length [1,2,3] => {0}" [show $ length [1,2,3]] 
0

nếu bạn chỉ muốn debug công cụ như:

inc :: Int -> Int 
inc x = [debug|1+x|] 

inc 2 
-- prints "1+x = 3" 
-- returns 3 

QuasiQuoter này có thể giúp:

{-# LANGUAGE TemplateHaskell #-} 
module Template where 
import Language.Haskell.TH 
import Language.Haskell.TH.Quote 
import Language.Haskell.TH.Syntax 
import Language.Haskell.Meta.Parse 
import Debug.Trace 

-- | e.g. f x = [debug|1+x|] 
debug :: QuasiQuoter 
debug = QuasiQuoter traceExp undefined undefined undefined 

-- | e.g. traceExp "1+x" -> [| trace "1+x = $([|1+x|])" (1+x) |] 
-- (or something) 
traceExp :: String -> Q Exp 
traceExp s = [|(trace $(showExp s) $(parseE s))|] 

-- | e.g. showExp "1+x" -> [| "1+x" ++ " = " ++ show (1+x) |] 
showExp :: String -> Q Exp 
showExp s = [|($(stringE s) ++ " = " ++ show $(parseE s))|] 

-- | e.g. parseE "1+x" -> (UInfixE (LitE (IntegerL 1)) (VarE +) (VarE x)) 
parseE :: String -> Q Exp 
parseE = return . either (const undefined) id . parseExp 

-- $ cabal install haskell-src-exts 
-- $ cabal install haskell-src-meta 

các biến được bắt tự động. Tôi đã viết nó trong khi học mẫu Haskell, nhưng debug không hoạt động để gỡ lỗi nội dung trong quá trình phát triển.

0

Tôi đã đăng khoảng fmt thư viện định dạng gần đây trong my answer to another question. Với thư viện này bạn có thể viết nội suy như thế này:

> "There are "+|n|+" million bicycles in "+|city|+"." 

Mặc dù, bạn có thể cũng quan tâm đến một số thư viện TH với Quoters Quasi:

https://hackage.haskell.org/package/interpolate-0.1.1/docs/Data-String-Interpolate.html

Mặc dù, thư viện này là rất chậm so với fmt.

Các vấn đề liên quan