我有这个F-Algebra(在之前的一个问题中介绍过),我想对它进行有效的代数.通过绝望的审判,我设法将一个有效的monadic catamorphism放在一起.我想知道它是否可以推广到一个应用程序,如果不是,为什么.
这就是我定义的方式Traversable:
instance Traversable Expr where
traverse f (Branch xs) = fmap Branch $ traverse f xs
traverse f (Leaf i ) = pure $ Leaf i
Run Code Online (Sandbox Code Playgroud)
这是monadic catamorphism:
type AlgebraM a f b = a b -> f b
cataM :: (Monad f, Traversable a) => AlgebraM a f b -> Fix a -> f b
cataM f x = f =<< (traverse (cataM f) . unFix $ x)
Run Code Online (Sandbox Code Playgroud)
这就是它的工作原理:
? let printAndReturn x …Run Code Online (Sandbox Code Playgroud) 我有一个数据结构,如表达式树或图形.我想添加一些"度量"函数,例如depth和size.
如何最好地输入这些功能?
我看到以下三种变体具有大致相同的用途:
depth :: Expr -> Intdepth :: Expr -> Integerdepth :: Num a => Expr -> a我有以下几点考虑因素:
我正在看base并fgl作为例子,他们一直使用Int,但Data.List也有genericLength返回类型的多态性等功能,我想也许这些generic功能的添加可能反映了我应该尊重的现代化趋势并加强.
类似的思想运动在一些广泛使用的库中是显而易见的,当用户需要几种可能的返回类型选择时,提供具有相同功能的全面功能集(例如,xml-conduit提供接受懒惰和严格类型的解析器的解析器).任一ByteString或Text).
Integer总体而言Int,这是一个更好的类型,我有时会发现我需要将一个列表的长度投入到一个列表中Integer,比如因为运行的algorighm Integer需要考虑这个长度.
使函数返回Integral意味着这些函数是多态的,并且可能会降低性能.我不太了解所有细节,但是,据我所知,可能会有一些运行时成本,而且多态事物更难记住.
什么是公认的最佳做法?哪个部分是由于遗留和兼容性考虑因素?(即如果Data.List今天设计,那么什么类型的功能length会有?)我是否错过任何优点和缺点?
有一个程序通过重复覆盖stderr. 操作如下:
当它想s用另一行覆盖一行时s',它s'用空格s填充,直到它至少与“回车”字符一样长:
n <- gets lastLineLength
let s'Padded | 0 < n = '\r': s' ++ replicate (n - length s') ' '
| otherwise = s'
hPutStr stderr s'Padded
Run Code Online (Sandbox Code Playgroud)这工作得很好。(虽然我个人没有在通常的 Linux 终端以外的情况下测试过它。)
我着手改进这个程序,用String一种Doc类型来代替普通的,ansi-wl-pprint这样我就可以用颜色来绘制文本,就像最近的 GHC 运动一样。像这样的库可能有点矫枉过正,因为我只需要一次输出几行,而且没有任何缩进,但我想尝试一下它的抽象着色设施。但是,我认为这个库(或任何漂亮的打印库)不会具有旨在擦除以前打印的Docs 的功能。
我想到的一种解决方案是Doc将 a渲染为 aString并测量其长度。但是,我将不得不为颜色代码打折;此外,这总体上是对库提供的抽象的侵入:具体来说,我将不得不依赖这样一个假设,即我手动执行的渲染将与hPutDoc.
我是否应该完全放弃该库并继续处理Strings,手动输入 ANSI 转义序列和回车?有没有更好的方法来覆盖以前的输出?我欢迎任何建议。
考虑以下count将类型级自然数映射到值级自然数的方法:
{-# LANGUAGE
DataKinds
, KindSignatures
, PolyKinds
, FlexibleInstances
, FlexibleContexts
, ScopedTypeVariables
#-}
module Nat where
data Nat = Z | S Nat
data Proxy (a :: k) = Proxy
class Count a where
count :: a -> Int
instance Count (Proxy Z) where
count _ = 0
instance Count (Proxy n) => Count (Proxy (S n)) where
count _ = succ $ count (Proxy :: Proxy n)
Run Code Online (Sandbox Code Playgroud)
它似乎在repl中工作:
? count (Proxy :: Proxy (S(S(S Z))) …Run Code Online (Sandbox Code Playgroud) 例如,假设我想读一条线并敲响钟声:
? getLine >> putChar '\007'
How lang and dreary is the night when I am frae my Dearie.
-- Blip and `()`. The line is lost.
? getLine >>= (\x -> putChar '\007' >> return x
I restless lie frae e'en to morn though I were ne'er sae weary.
"I restless lie frae e'en to morn though I were ne'er sae weary."
-- A line and also a blip side effect.
Run Code Online (Sandbox Code Playgroud)
这个想法似乎有很多共同之处const,唯一的区别是给出的值是有效的,并且都被执行,即使只保留了第一个动作的值.(与之不同>>,它保留了第二个的价值.)我的意思是:
? …Run Code Online (Sandbox Code Playgroud) 为什么 一个人可能会说这zip是一个Applicative通常的例子ZipList.我对它不满意,因为它不安全.我也不满意Align,因为它是无所不包的,过于复杂,而且对于通常情况来说不够具体.
合法类 Haskell中的某些类型类可能被称为合法类.这意味着他们必须拥有必须持有的平等 - 一个阶级的法律.通常这些规律来自编程方面的范畴理论概念化.例如,Monad是通过同名类别理论设备对计算 进行概念化(无论是什么意思).
重叠事物 想要处理事物的通常操作是将它们放在彼此之上,如果它们是幺半群,它们将融合在一起.
例子:
没有足够的定律 这个概念的概念化是通过monoidal仿函数和相应的Applicative类型类.然而,存在令人烦恼的复杂性,因为通常有两种方式来定义Applicative两者看起来都合适.为什么这样?我建议答案是"法律不够".
例子:
对于算术:
Sum独异的是实际的"内切半群".它对于亲属来说是合法的.例如,你无法总结质量和力量.Product半群需要维数a和b多项维度c.将质量和力量相乘是合法的,让我们变得温暖.因此,monoid的正确选择可以从类型中推断出来.
对于列表:
对于矩阵:
ZipMatrix沿着上述线条的定义ZipList似乎没有吸引力. …作为练习,我尝试自己编写此代码,但是我被卡住了,不知道代码中的错误在哪里。
module Hf where
--sumSquaresTo :: Integer -> Integer
--sumSquaresTo x = sum [ n^2 | n <- [1..x] ]
divides a b = b `mod` a == 0
divisors a = [n | n <- [1..a], n `divides` a ]
lnko :: Integer -> Integer -> Integer
lnko a b = [n | n <- [1..max(a b)], (n `divides` a) && (n `divides` b) ]
Run Code Online (Sandbox Code Playgroud)
GHCI输出:
error:
* Couldn't match expected type `Integer'
with actual type `[a0 -> a0]' …Run Code Online (Sandbox Code Playgroud) 确实如此:
? :i Applicative
class Functor f => Applicative (f :: * -> *) where
Run Code Online (Sandbox Code Playgroud)
同时:
fmap f x = pure f <*> x
Run Code Online (Sandbox Code Playgroud)
- 根据Applicative我们的法律,我们可以定义fmap来自pure&<*>.
我不明白为什么我要不厌其烦地定义了fmap我想要的,每次Applicative如果,真的,fmap可以自动的规定设立pure和<*>.
我认为,如果pure或<*>某种程度上依赖于定义,那将是必要的,fmap但我不明白为什么他们必须这样做.
我编写了这个函数来计算Collatz序列,我看到执行的时间差别很大,这取决于我给它的旋转.显然它与"memoization"有关,但我很难理解它是什么以及它是如何工作的,不幸的是,关于HaskellWiki的相关文章以及它链接到的论文都被证明不是很容易克服.他们讨论了高度非外行 - 无差别树构造的相对表现的错综复杂的细节,而我想念的必须是这些来源忽略的一些非常基本的,非常微不足道的观点.
这是代码.这是一个完整的程序,随时可以构建和执行.
module Main where
import Data.Function
import Data.List (maximumBy)
size :: (Integral a) => a
size = 10 ^ 6
-- Nail the basics.
collatz :: Integral a => a -> a
collatz n | even n = n `div` 2
| otherwise = n * 3 + 1
recollatz :: Integral a => a -> a
recollatz = fix $ \f x -> if (x /= 1)
then f (collatz x)
else x
-- Now, I …Run Code Online (Sandbox Code Playgroud) 我的意思是像列表这样的设备:
mempty = [ ]
lift x = [x]
mappend = (++)
Run Code Online (Sandbox Code Playgroud)
仅仅是IsList吗?
haskell ×10
typeclass ×2
applicative ×1
catamorphism ×1
functor ×1
list ×1
memoization ×1
monads ×1
monoids ×1
pretty-print ×1
recursion ×1
runtime ×1
terminal ×1