我想知道做这样的事情是否不好?
data Alignment = LeftAl | CenterAl | RightAl
type Delimiter = Char
type Width = Int
setW :: Width -> Alignment -> Delimiter -> String -> String
Run Code Online (Sandbox Code Playgroud)
而不是像这样:
setW :: Int -> Char -> Char -> String -> String
Run Code Online (Sandbox Code Playgroud)
我确实知道,有效地重构这些类型什么也没做,只是占用几行以换取更清晰的代码。但是,如果我将类型Delimiter
用于多种功能,那么对于导入此模块或稍后阅读代码的人来说,这将更加清晰。
我是Haskell的新手,所以我不知道这种类型的好方法是什么。如果这不是一个好主意,或者有一些可以提高清晰度的方法是可取的,那将是什么?
我知道类型类对于组织数据和类型检查等非常有用,但是除了序言中已经包含的内容之外,是否需要定义自己的类?
在几乎任何情况下,只要定义一个数据或新类型,无论如何都会获得几乎相同的效果。使用内置的“ Ord”,“ Eq”,“ Show”等,似乎足以完成您想对类进行的任何操作。
当我在Haskell中查找项目的类时,会得到很多类似的示例类:
class Foo a where
bar :: a -> a -> Bool
Run Code Online (Sandbox Code Playgroud)
如果有使用类型类的理由,那么有没有人有一个好的项目供初学者练习使用它们或为它们提供一些好的形式指南?
我想做的是定义一个这样的函数:
[f 0, f f 0, f f f 0, f f f f 0, f f f f f 0..]
Run Code Online (Sandbox Code Playgroud)
换句话说,每个元素是通过函数运行的最后一个元素。
我已经尝试过几次,以通过调用带有预定义的前几个元素的列表来使它以类似于我在Haskell中看到的斐波那契数列的方式工作:
fib = 0 : 1 : zipWith (+) fib (tail fib)
ls = 0 : f 0 : f (last ls)
Run Code Online (Sandbox Code Playgroud)
如果我将f定义为简单的addOne函数,例如:
f =(+1)
我收到此错误:
<interactive>:124:5: error:
* Occurs check: cannot construct the infinite type: a ~ [a]
Expected type: [[a]]
Actual type: [a]
* In the expression: 0 : (f 0) : f (last y)
In …
Run Code Online (Sandbox Code Playgroud) 我在这里发现了一个类似的问题,询问的几乎是同一件事,但并非完全相同。
我的问题是如何将类型(a-> Bool)的函数列表组合为也是(a-> Bool)的一个函数。
例如
compose :: [(a -> Bool)] -> (a -> Bool)
compose [] = **?**
compose (x:xs) = x **?** compose xs
Run Code Online (Sandbox Code Playgroud)
与此类似的问题是采用三个功能并将它们混合在一起,如下所示:
newFunction x f g y = f x || g x || y x
Run Code Online (Sandbox Code Playgroud)
但这非常有限,因为您必须提供特定数量的函数,并且它不返回另一个函数,而是返回布尔值。我本质上想要一个函数,该函数可以为我提供上面的函数,而没有函数作为参数。
我尝试弄乱Monoids来完成这项工作,但首先遇到了将函数包装到Monoid中的问题,更不用说像newFunction一样将它们组合在一起了。
有没有一种方法可以将相同类型的功能列表(a-> Bool)组成一个相同类型的功能?
所以这个问题很简单,但我似乎无法理解这个概念。
要组成普通函数,可以执行以下操作:
lowerNoSpaces = filter (/= ' ') . map toLower
Run Code Online (Sandbox Code Playgroud)
但是,有时候,这有时行不通:
myConcatMap = concat . map
Run Code Online (Sandbox Code Playgroud)
它给出了错误:
<interactive>:236:1: error:
* Non type-variable argument
in the constraint: Foldable ((->) [a1])
(Use FlexibleContexts to permit this)
* When checking the inferred type
concattMap :: forall a1 a2.
Foldable ((->) [a1]) =>
(a1 -> a2) -> [a2]
Run Code Online (Sandbox Code Playgroud)
但是当相同的函数表示为:
myConcatMap = (concat .) . map
Run Code Online (Sandbox Code Playgroud)
它完全按预期工作。
我知道这是有原因的,但是我一直盯着它看了一阵子,但仍然不太明白为什么原版不起作用而本原版却起作用。
为什么会有两个“。” 的?
我有一个简单的程序,它仅从用户处获取一个字符串和一个密钥,并使用凯撒密码函数对字符串进行加密。该函数本身起作用,所以我不会显示源代码。问题是,当编译器编译程序时,它将允许我输入所有的getLines,然后在输入所有内容后,程序将打印所有的putStr和putStrLn,然后关闭。仅当使用“ runhaskell”执行程序或将其编译并执行为exe时才发生这种情况。不在口译员中。这是程序:
main = do
choice <- prompt "Would you like to encrypt (1) or decrypt (2)? "
if choice == "1" then do
encrypt <- prompt "Enter code for encryption: "
k <- prompt "Enter key for the code: "
let key = read k in
putStrLn ("Encrypted message: " ++ (caesar key encrypt) ++ "\n")
else do
decrypt <- prompt "Enter code for decryption: "
k <- prompt "Enter key for the code: "
let key = read …
Run Code Online (Sandbox Code Playgroud) 我正在尝试使用随机数对任何a的列表进行洗牌。我在这里问这个问题的原因是因为我已经创建了一个函数,但无法弄清楚为什么它确实不起作用。
pick :: [a] -> IO a
pick xs = do
n <- randomRIO (0, length xs - 1)
return $ xs !! n
shuffle :: [a] -> [IO a]
shuffle ls = do
x <- pick ls
let y = remove x ls
(return x) : shuffle y
-- Remove an element from a list (Only first appearance)
remove :: (Eq a) => a -> [a] -> [a]
remove _ [] = []
remove r (x:xs) = if x …
Run Code Online (Sandbox Code Playgroud)