2014-08-28 15 views
10

Có cách nào để giảm đau do đơn giản hóa biểu hiện không?Học Haskell - Cách đơn giản hóa các biểu thức?

Ví dụ, đưa ra biểu thức này:

(+) <$> a <*> b $ 1 

Tôi rất thích nhìn thấy một công cụ mà có thể giải thích ý nghĩa của nó. Đó là khá mất thời gian cho người mới bắt đầu (tìm đúng nghĩa hàm dụ trong nguồn, kiểm tra khai thác được ưu tiên) để đơn giản hóa biểu thức với tất cả các bước liên quan:

fmap (+) a <*> b $ 1 

Xem definition trong Data.Functor

(.) (+) a <*> b $ 1 

Xem fmap trong Control.Monad.Instances cho instance Functor ((->) r)

v.v.

EDIT: Để làm rõ, tôi đang tìm cách viết lại biểu thức bằng cách sử dụng định nghĩa hàm thực tế để người mới có thể hiểu kết quả của biểu thức này. Làm thế nào để nói rằng (<$>) = fmap ở đây? Tôi không biết cách tìm một định nghĩa cá thể (nguồn) cụ thể bằng cách sử dụng hoogle và các công cụ khác.

CHỈNH SỬA: Thay đổi biểu thức gốc không chính xác để phù hợp với giảm sau.

Trả lời

3

Bắt đầu ghci, :cd vào thư mục gốc của nguồn bạn đang đọc, :load module bạn quan tâm, và sử dụng lệnh :i để có được các thông tin:

ghci> :i <$> 
(<$>) :: Functor f => (a -> b) -> f a -> f b 
    -- Defined in `Data.Functor' 
infixl 4 <$> 
ghci> :i $ 
($) :: (a -> b) -> a -> b -- Defined in `GHC.Base' 
infixr 0 $ 
ghci> :i . 
(.) :: (b -> c) -> (a -> b) -> a -> c -- Defined in `GHC.Base' 
infixr 9 . 

Điều đó nói với bạn loại, nơi nó được xác định, kết hợp (infixl hoặc infixr) và ưu tiên (số, cao hơn là chặt chẽ hơn). Vì vậy, (*10) <$> a $ 1 được đọc là ((*10) <$> a) $ 1.

Khi bạn :load một mô-đun, tất cả các tên nằm trong phạm vi bên trong mô-đun đó sẽ nằm trong phạm vi bên trong ghci. Một nơi mà điều này có thể gây phiền nhiễu là nếu bạn có một lỗi trong mã, sau đó bạn không thể :i bất cứ điều gì bên trong nó. Trong những trường hợp này, bạn có thể nhận xét các dòng, sử dụng undefined và có thể cũng sử dụng các lỗ đã nhập như behlkir gợi ý (chưa chơi với những thứ quá nhiều).

Khi bạn đang ở đó, hãy thử lệnh :? trong ghci.

6

Tôi thấy rằng một cách dễ dàng là sử dụng typed holes sẵn trong GHCi 7.8:

> (*10) <$> _a $ 1 
Found hole ‘_a’ with type: s0 -> b 
Where: ‘s0’ is an ambiguous type variable 
     ‘b’ is a rigid type variable bound by 
      the inferred type of it :: b at <interactive>:4:1 
Relevant bindings include it :: b (bound at <interactive>:4:1) 
In the second argument of ‘(<$>)’, namely ‘_a’ 
In the expression: (* 10) <$> _a 
In the expression: (* 10) <$> _a $ 1 

Vì vậy, đây nói với tôi rằng a :: s0 -> b. Tiếp theo là tìm ra thứ tự của các nhà khai thác:

> :i (<$>) 
(<$>) :: Functor f => (a -> b) -> f a -> f b 
infixl 4 <$> 
> :i ($) 
($) :: (a -> b) -> a -> b 
infixr 0 $ 

Vì vậy, đây nói rằng $ rất phải kết hợp, và cho đó là gõ chúng ta thấy rằng đó là số đầu tiên phải là một chức năng, vì vậy a phải là một chức năng (xác nhận kép). Điều này có nghĩa là (*10) <$> a $ 1 giống với ((*10) <$> a) $ 1, vì vậy, chúng tôi sẽ tập trung vào (*10) <$> a trước tiên.

> :t ((*10) <$>) 
((*10) <$>) :: (Num a, Functor f) => f a -> f a 
> :t (<$> _a) 
Found hole ‘_a’ with type: f a 
Where: ‘a’ is a rigid type variable bound by 
      the inferred type of it :: (a -> b) -> f b at Top level 
     ‘f’ is a rigid type variable bound by 
      the inferred type of it :: (a -> b) -> f b at Top level 
In the second argument of ‘(<$>)’, namely ‘_a’ 
In the expression: (<$> _a) 

Vì vậy, chúng tôi cần a để làm người viết thư. Trường hợp có sẵn là gì?

> :i Functor 
class Functor (f :: * -> *) where 
    fmap :: (a -> b) -> f a -> f b 
    (<$) :: a -> f b -> f a 
     -- Defined in ‘GHC.Base’ 
instance Functor Maybe -- Defined in ‘Data.Maybe’ 
instance Functor (Either a) -- Defined in ‘Data.Either’ 
instance Functor ZipList -- Defined in ‘Control.Applicative’ 
instance Monad m => Functor (WrappedMonad m) 
    -- Defined in ‘Control.Applicative’ 
instance Control.Arrow.Arrow a => Functor (WrappedArrow a b) 
    -- Defined in ‘Control.Applicative’ 
instance Functor (Const m) -- Defined in ‘Control.Applicative’ 
instance Functor [] -- Defined in ‘GHC.Base’ 
instance Functor IO -- Defined in ‘GHC.Base’ 
instance Functor ((->) r) -- Defined in ‘GHC.Base’ 
instance Functor ((,) a) -- Defined in ‘GHC.Base’ 

Vì vậy (->) r sẽ xảy ra là một, mà là awesome bởi vì chúng tôi biết a có phải là một chức năng. Từ ràng buộc Num, chúng tôi có thể xác định rằng r phải giống như Num a => a. Điều này có nghĩa là (*10) <$> a :: Num a => a -> a. Từ đó, chúng tôi áp dụng 1 cho nó và chúng tôi sẽ nhận được (*10) <$> a $ 1 :: Num a, trong đó a là một số chức năng không xác định.

Tất cả điều này có thể phát hiện được bằng GHCi sử dụng :t:i cùng với các lỗ đã nhập. Chắc chắn, có một số công bằng của các bước liên quan, nhưng nó không bao giờ thất bại khi bạn đang cố gắng để phá vỡ một biểu thức phức tạp, chỉ cần nhìn vào các loại biểu thức phụ khác nhau.

5

GHCi đã được đề xuất một cách tuyệt vời và chính xác, và tôi cũng đề xuất nó.

Tôi cũng muốn đề nghị Hoogle, bởi vì với bật, tìm kiếm tức thời (ở thanh bên đầu ở bên phải có một nút cho nó), bạn có thể tìm kiếm cho các chức năng rất nhanh chóng, nó có thể cung cấp nhiều, nhiều nhiều thông tin hơn GHCi và phần tốt nhất là bạn không phải đề cập đến các mô-đun để tìm kiếm trong chúng . Điều này trái ngược với GHCi nơi bạn phải nhập trước:

ghci> :t pure 
<interactive>:1:1: Not in scope: ‘pure’ 
ghci> :m +Control.Applicative 
ghci> :t pure 
pure :: Applicative f => a -> f a 

Liên kết Hoogle ở ​​trên chỉ là một (từ trang Haskell.org). Hoogle là chương trình bạn cũng có thể cài đặt trên máy của mình (cabal install hoogle) và thực hiện truy vấn từ dòng lệnh (hoogle your-query).
Sidenote: bạn phải chạy hoogle data để thu thập thông tin trước. Nó yêu cầu wget/curl, vì vậy nếu bạn đang sử dụng Windows, bạn có thể cần phải có được this trong đường dẫn của mình trước tiên (hoặc curl cho Windows, tất nhiên). Trên Linux, nó hầu như luôn được tích hợp sẵn (nếu bạn không có nó trên Linux, chỉ cần apt-get nó). Tôi không bao giờ sử dụng Hoogle từ dòng lệnh bằng cách này, nó chỉ đơn giản là không thể truy cập được, nhưng nó vẫn có thể rất hữu ích vì một số trình soạn thảo văn bản và plugin của họ có thể tận dụng nó. Hoặc bạn có thể sử dụng FPComplete's Hoogle mà đôi khi thỏa mãn hơn (bởi vì theo kinh nghiệm của tôi, nó đã nhận thức được nhiều thư viện của bên thứ ba hơn. Tôi chỉ sử dụng nó trong những "phiên làm việc").

Ngoài ra còn có Hayoo! bằng cách này.

Trong Hoogle bạn có thể> 95% thời gian sẽ không phải thực hiện việc này nhưng +Module để nhập mô-đun nếu vì lý do nào đó không được tìm kiếm (đôi khi là thư viện của bên thứ ba) .
Bạn cũng có thể lọc các mô-đun theo -Module.
Ví dụ: destroyTheWorld +World.Destroyer -World.Destroyer.Mercy để tìm destroyTheWorld và chắc chắn rằng bạn đang không nhìn vào cách thương xót để làm điều đó (này đi kèm rất tiện dụng với các module với tên chức năng tương tự cho các phiên bản khác nhau, như những người thân trong Data.ByteString & Data.ByteString.Lazy, Data.Vector & Data.Vector.Mutable, v.v.).Oh và một lợi thế tuyệt vời nữa của Hoogle là không chỉ nó cho bạn thấy chữ ký của hàm, nó cũng có thể đưa bạn đến trang Haddock của mô-đun, vì vậy bạn cũng có được tài liệu + trong các trang đó, khi có sẵn, bạn có thể nhấp vào trên "Nguồn" ở bên phải của mọi chức năng để xem cách nó được triển khai để biết thêm thông tin.

Điều này nằm ngoài phạm vi của câu hỏi, nhưng Hoogle cũng được sử dụng để truy vấn các chữ ký chức năng mà chỉ là .. mindblowingly hữu ích. Nếu tôi muốn một hàm lấy số chỉ mục và danh sách và cung cấp cho tôi phần tử trong chỉ mục đó và tôi tự hỏi nếu nó đã được tích hợp sẵn, tôi có thể tìm kiếm nó trong vài giây.
Tôi biết rằng hàm này lấy một số và danh sách, và cung cấp cho tôi một phần tử trong danh sách để chữ ký hàm phải trông giống như sau: Int -> [a] -> a (hoặc tổng quát: Num a => a -> [b] -> b) và cả hai trường hợp đều hiển thị một chức năng cho điều đó ((!!)genericIndex).

Trường hợp GHCi có ưu thế là bạn có thể chơi với các biểu thức, khám phá chúng, v.v. Rất nhiều lần khi xử lý các hàm trừu tượng có nghĩa là rất nhiều.
Có thể :l (oad) rất hữu ích.

Nếu bạn chỉ đang tìm kiếm chữ ký chức năng, bạn có thể kết hợp cả Hoogle và GHCi.
Trong GHCi bạn có thể nhập :! cmd và GHCi sẽ thực thi cmd trong dòng lệnh và in kết quả. Điều đó có nghĩa là bạn cũng có thể sử dụng Hoogle trong GHCi, ví dụ: :! hoogle void.

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